1. 程式人生 > >【POJ3126 Prime Path】【POJ 3087 Shuffle'm Up】【UVA 11624 Fire!】【POJ 3984 迷宮問題】

【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;
}