【POJ3126 Prime Path】【POJ 3087 Shuffle'm Up】【UVA 11624 Fire!】【POJ 3984 迷宮問題】
POJ3126Prime Path
給定兩個四位素數a b,要求把a變換到b
變換的過程要 每次變換出來的數都是一個 四位素數,而且當前這步的變換所得的素數 與 前一步得到的素數 只能有一個位不同,而且每步得到的素數都不能重複。
///果不其然各種姿勢操T了,在暴力的時候,呼叫了太多的C++庫檔案 #include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <sstream> #include <queue> using namespace std; const int maxn=2e5; bool a[maxn]; bool prime[maxn]; bool vis[maxn]; int step[maxn]; string n,m; int cnt=0;//四位數的素數也就有1061個 void getprime(){ memset(a,false,sizeof(a)); memset(prime,false,sizeof(prime)); for(int i=2; i<10000; ++i){ if(!a[i]){ if(i>=1000) prime[i]=true; for(int j=i*i; j<10000; j+=i) a[j]=true; } } } void bfs(){ memset(vis,false,sizeof(vis)); string tmp; queue<string>q; q.push(m); int mm=atoi(m.c_str()); vis[mm]=1; step[mm]=0; int k=0; while(!q.empty()){ string p=q.front(); q.pop(); int pp=atoi(p.c_str()); if(p==n){ printf("%d\n",step[pp]); return ; } for(int i=0; i<=9; ++i){ for( k=0; k<4; ++k){ tmp.clear(); for(int j=0; j<k; ++j) tmp+=p[j]; stringstream ss; ss<<i; tmp+=ss.str();//tmp+=std::to_string(i); for(int j=k+1; j<4; ++j) tmp+=p[j]; int tmpp=atoi(tmp.c_str()); if(prime[tmpp]&&!vis[tmpp]){ q.push(tmp); step[tmpp]=step[pp]+1; vis[tmpp]=true; } } } } printf("Impossible\n"); } int main(){ getprime(); int t; scanf("%d",&t); while(t--){ cin>>m>>n; bfs(); } return 0; }
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <sstream> #include <queue> using namespace std; const int maxn=2e5; bool a[maxn]; bool prime[maxn]; bool vis[maxn]; int step[maxn]; int n,m; int cnt=0;//四位數的素數也就有1061個 void getprime(){ memset(a,false,sizeof(a)); memset(prime,false,sizeof(prime)); for(int i=2; i<10000; ++i){ if(!a[i]){ if(i>=1000) prime[i]=true; for(int j=i*i; j<10000; j+=i) a[j]=true; } } } //將number的倒數第pos位置變為val int get(int num,int pos,int val){ switch(pos){ case 0:return num/10*10+val; case 1:return num/100*100+val*10+num%10; case 2:return num/1000*1000+val*100+num%100; case 3:return num%1000+val*1000; } } void bfs(){ memset(vis,false,sizeof(vis)); queue<int>q; q.push(m); vis[m]=1; step[m]=0; int k=0; while(!q.empty()){ int p=q.front(); q.pop(); if(p==n){ printf("%d\n",step[p]); return ; } for(int i=0; i<=9; ++i){ for( k=0; k<4; ++k){ if(k==3&&i==0) continue; int tmp=get(p,k,i); if(prime[tmp]&&!vis[tmp]){ q.push(tmp); step[tmp]=step[p]+1; vis[tmp]=true; } } } } printf("Impossible\n"); } int main(){ int t; getprime(); scanf("%d",&t); while(t--){ scanf("%d%d",&m,&n); bfs(); } return 0; }
POJ 3087 Shuffle'm Up
已知兩堆牌s1和s2的初始狀態, 其牌數均為c,按給定規則能將他們相互交叉組合成一堆牌s12,再將s12的最底下的c塊牌歸為s1,最頂的c塊牌歸為s2,依此迴圈下去。
現在輸入s1和s2的初始狀態 以及 預想的最終狀態s12
問s1 s2經過多少次洗牌之後,最終能達到狀態s12,若永遠不可能相同,則輸出"-1"。
模擬:
#include <cstdio> #include <iostream> #include <queue> #include <map> #include <cstring> using namespace std; int main() { int t; scanf("%d",&t); for(int ca=1;ca<=t;++ca){ int n; char s1[1005],s2[1005],en[10000]; map<string,bool >m; scanf("%d",&n); scanf("%s",s1); scanf("%s",s2); scanf("%s",en); int step=0; int times=1000,ti=0; while(true){ ti++; char s[1000]; int pc=0; for(int i=0;i<n;++i){ s[pc++]=s2[i]; s[pc++]=s1[i]; } s[pc]='\0'; step++; if(!strcmp(s,en)){ printf("%d %d\n",ca,step); break; } if(m[s]){ printf("%d %d\n",ca,-1); break; } m[s]=true; strncpy(s1,s,n); s1[n]='\0'; strncpy(s2,s+n,n); s2[n]='\0'; if(ti==times){ printf("%d %d\n",ca,-1); break; } } } return 0; }
dfs:
#include <cstdio>
#include <iostream>
#include <queue>
#include <map>
#include <cstring>
using namespace std;
int ans,n;
map<string,int>m;
char s1[200],s2[200],s3[200];
void dfs(char s[],int step){
if((ans=-1&&step>=ans)||m[s])return;
if(m[s])return;
if(!strcmp(s,s3)){ans=step;return ;}
m[s]=true;
char ss[200]="";
int op=0;
for(int i=0;i<n;++i)
{
ss[op++]=s[i+n];
ss[op++]=s[i];
}
dfs(ss,step+1);
}
int main(){
int t;
char ss[200];
scanf("%d",&t);
for(int ca=1;ca<=t;++ca){
ans=-1;
m.clear();// map<>
scanf("%d",&n);
scanf("%s",s1);
scanf("%s",s2);
scanf("%s",ss);
char s[200];
int op=0;
for(int i=0;i<n;++i){
s[op++]=s1[i];
s[op++]=s2[i];
}
dfs(s,1);
printf("%d %d\n",ca,ans);
}
}
UVA 11624 Fire!
題意:幫助joe走出一個大火蔓延的迷宮,其中joe每分鐘可往上下左右四個方向之一走,所有著火的格子都會蔓延(空格與著火格有公共邊,下一分鐘這個空格也會著火)。迷宮中有一些障礙格,joe和火都無法進入,當joe走到一個邊界的格子我們認為他走出了迷宮
輸出R行C列的迷宮,#表示牆,.表示空地,J表示joe,F是著火格
如果能走出,輸出最少時間否則,impossible
感覺很經典的一個問題,在處理每個點著火的時間的時候,卻發現假若當前這個點之前已經被火著過一次怎麼辦了,在一想這就是簡單的bfs最優性質決定的,用寬搜的時候就已經保證了在搜尋過的著火點已經是最優的了
#include <iostream>
#include<cstdio>
#include <iostream>
#include <cstring>
#include <queue>
using namespace std;
typedef long long ll;
const int maxn=(int)1e3+10;
char map[maxn][maxn];
int step[maxn][maxn];
int vis[maxn][maxn];
int n,m;
ll inf=0x3f3f3f3f;
int dir[4][2]={{1,0},{0,1},{0,-1},{-1,0}};
queue<pair<int,int> >q;
void clear(queue<pair<int,int> >& q){
queue<pair<int,int> > empty;
swap(empty,q);
}
void bfs_fire(){
while(!q.empty()){
pair<int,int> p=q.front();
q.pop();
int x=p.first,y=p.second;
// vis[x][y]=1;//vis[p.first][p.second]=1; 如果一直用first second去查詢肯定會耗費時間
pair<int,int> tmp;
for(int i=0;i<4;++i){
int dx=x+dir[i][0];
int dy=y+dir[i][1];
if(dx<1||dx>n||dy<1||dy>m||step[dx][dy]!=inf)continue;
if(map[dx][dy]=='#')continue;
tmp.first=dx,tmp.second=dy;
step[dx][dy]=step[x][y]+1;
q.push(tmp);
}
}
}
int pe[maxn][maxn];
void bfs_person(){
pair<int,int > p;
while(!q.empty()){
p=q.front();
q.pop();
int x=p.first,y=p.second;
if(x==1||x==n||y==1||y==m){
printf("%d\n",pe[x][y]+1);
return ;
}
// vis[x][y]=1;
for(int i=0;i<4;++i){
int dx=x+dir[i][0];
int dy=y+dir[i][1];
if(dx<1||dx>n||dy<1||dy>m||pe[dx][dy]!=inf)continue;
if(map[dx][dy]=='#')continue;
if( (pe[x][y]+1<step[dx][dy]) ){//&&step[dx][dy]!=inf wa
//加上這個!=inf開始是為了防止更新到障礙物所在的方格,其實上面的!=#已經判斷了,不加也可以,不過加上他之後竟然wa掉,那就是說存在資料火到不了的網格人可以到,障礙物把火源包圍了的這種情況
pe[dx][dy]=pe[x][y]+1;
q.push(make_pair(dx,dy));
}
}
}
printf("IMPOSSIBLE\n");return ;
}
void solve(){
memset(step,inf,sizeof(step));
//memset(vis,0,sizeof(vis));
while(!q.empty())q.pop();
//clear(q);
// for(int i=1;i<=n;++i){
// for(int j=1;j<=m;++j)
// cout<<map[i][j];
// cout<<endl;
// }
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j){
if(map[i][j]=='F'){
step[i][j]=0;
q.push(make_pair(i,j));
}
}
bfs_fire();
// for(int i=1;i<=n;++i){
// for(int j=1;j<=m;++j){
// cout<<step[i][j]<<' ';
// }
// cout<<endl;
// }
// memset(vis,0,sizeof(vis));
memset(pe,inf,sizeof(pe));
// clear(q);
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j){
if(map[i][j]=='J'){
pe[i][j]=0;
q.push(make_pair(i,j));
break;
}
}
bfs_person();
// for(int i=1;i<=n;++i){
// for(int j=1;j<=m;++j)
// cout<<pe[i][j]<<' ';
// cout<<endl;
// }
//return;
}
int main(){
int t;
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i){
scanf("%s",(map[i]+1));
}
solve();
}
return 0;
}
//除了上面的那個inf問題還有就是開始定義了兩個vis的初始化,一開始就T掉,
POJ 3984 迷宮問題
定義一個二維陣列:
int maze[5][5] = {
0, 1, 0, 0, 0,
0, 1, 0, 1, 0,
0, 0, 0, 0, 0,
0, 1, 1, 1, 0,
0, 0, 0, 1, 0,
};
它表示一個迷宮,其中的1表示牆壁,0表示可以走的路,只能橫著走或豎著走,不能斜著走,要求程式設計序找出從左上角到右下角的最短路線。
Input
一個5 × 5的二維陣列,表示一個迷宮。資料保證有唯一解。
Output
左上角到右下角的最短路徑,格式如樣例所示。
Sample Input
0 1 0 0 0
0 1 0 1 0
0 0 0 0 0
0 1 1 1 0
0 0 0 1 0
Sample Output
(0, 0)
(1, 0)
(2, 0)
(2, 1)
(2, 2)
(2, 3)
(2, 4)
(3, 4)
(4, 4)
#include <cstdio>
#include <iostream>
#include <queue>
//#include <bits/stdc++.h>
#include <cstring>
using namespace std;
int mat[5][5];
int dir[5][2]={{1,0},{0,1},{0,-1},{-1,0}};
struct node{
int x,y,pre;
}point[100];
void dfs(node p)
{
if(p.pre==-1){printf("(%d, %d)\n",p.x,p.y);return;}
dfs(point[p.pre]);
printf("(%d, %d)\n",p.x,p.y);
}
void bfs()
{
int x,y,dx,dy,pre=0,cur=1;
//queue<node> q;
point[0].x=0,point[0].y=0,point[0].pre=-1;
mat[0][0]=1;
while(pre<=cur){
if(point[pre].x==4&&point[pre].y==4){
dfs(point[pre]);
return ;
}
for(int i=0;i<4;++i){
dx=point[pre].x+dir[i][0];
dy=point[pre].y+dir[i][1];
if(dx<0||dx>=5||dy<0||dy>=5||mat[dx][dy])continue;
point[cur].x=dx,point[cur].y=dy,point[cur].pre=pre;
++cur;
}
++pre;
}
}
int main()
{
for(int i=0;i<5;++i)
for(int j=0;j<5;++j)
scanf("%d",&mat[i][j]);
bfs();
return 0;
}