搜索(DFS/BFS)

棋盘问题

poj - 1321

#include<cstdio>
using namespace std;
int n, k;
int ans = 0; 
int pic[10][10];
int cc[10];
void dfs(int r, int c, int num, int flag){//flag 标记是否选择 
	if(num == k){
		if(flag)
			cc[c] = 0;	//回溯 
		ans ++;
		return;
	}
	if(r == n-1){
		if(flag)
			cc[c] = 0; //回溯 
		return;
	}	
	dfs(r+1, 0, num, 0);//这行不选 
	for(int j = 0; j < n; ++ j){//选 
		if(pic[r+1][j] == '#' && cc[j] == 0){
			cc[j] = 1;
			dfs(r+1, j, num+1, 1);
		}			
	}
	if(flag)
		cc[c] = 0;//回溯 
}

int main(){
	while(scanf("%d %d", &n, &k)){
		getchar();
		if(n == -1 && k == -1)
			break;
		for(int i = 0; i < n; ++ i){
			for(int j = 0; j < n; ++ j)
				scanf("%c", &pic[i][j]);
			getchar();
		}
		ans = 0;
		for(int q = 0; q < n; ++ q){
			cc[q] = 0;
		}
		dfs(0, 0, 0, 0);//这行不选 
		for(int j = 0; j < n; ++ j){//这行选 
			for(int q = 0; q < n; ++ q){
				cc[q] = 0;
			}
			if(pic[0][j] == '#' && cc[j] == 0){
				cc[j] = 1;
				dfs(0, j, 1, 1);
			}			
		}
		printf("%d\n", ans);
	}
}

poj 1753

//最多 16个点 都选择, 每个点最多选一次,选两次就如同没选 
//样例的答案 : 4选择的四个点 
//0 0 
//1 1 
//1 3 
//2 0
#include<cstdio>
using namespace std;
const int INF = 0x3f3f3f3f;
int ans;
char ch;
int pic[5][5];
int vis[5][5];
int addx[5] = {0, 1, -1, 0, 0};//自己与周围要发生改变 
int addy[5] = {0, 0, 0, 1, -1};
int use[17][3];//用来存选择的点 

bool check1(){//判断是否棋盘上棋子都相同 
	for(int i = 0; i < 4; ++ i)
		for(int j = 0; j < 4; ++ j)
			if(pic[i][j] != pic[0][0])
				return false;
	return true;
}

bool check2(int x, int y){//判断边界 
	if(x >= 0 && x < 4 && y >= 0 && y < 4)	return true;
	return false;
}

void change(int x, int y){//改变棋子类型 
	for(int i = 0; i < 5; ++ i){
		int xx = x + addx[i];
		int yy = y + addy[i];
		if(check2(xx, yy)){
			pic[xx][yy] = !pic[xx][yy];
		}
	}
}

void dfs(int x, int y, int t, int flag){//t 表示步数,flag 表示该点是否有选择 
	vis[x][y] = 1;//已做过选择,接下来不会再选 
	if(t == ans){// 接下来的选择一定不满足 
		vis[x][y] = 0;
		return;
	}
	if(flag)//选择了就要改变 
		change(x, y);
//	if(flag)
//		use[t][0] = x, use[t][1] = y;
	if(check1()){
		//printf("ans\n\n\n");
		//printf("%d %d %d %d\n", x, y, t, flag);
		//for(int i = 1; i < 17; ++ i)
		//	printf("%d %d\n ", use[i][0], use[i][1]);
		//printf("\n");
		vis[x][y] = 0;//回溯 
		if(flag)
			change(x, y);//回溯 
//		if(flag)
//			use[t][0] = 0, use[t][1] = 0;
		if(t < ans)
			ans = t;
		return; 
	}
	int flagg = 1;
	for(int i = 0; i < 4; ++ i){
		for(int j = 0; j < 4; ++ j){
			if(vis[i][j] == 0){//找到下一个点 
				dfs(i, j, t, 0);//不选 
				dfs(i, j, t+1, 1);//选 
				flagg = 0;
				break;
			}
		}
		if(flagg == 0)
			break;
	}
	if(flag)
		change(x, y);//回溯 
//	if(flag)
//		use[t][0] = 0, use[t][1] = 0;
	vis[x][y] = 0;//回溯 
}

int main(){
	for(int i = 0; i < 4; ++ i){
		for(int j = 0; j < 4; ++ j){
			scanf("%c", &ch);
			if(ch == 'w')
				pic[i][j] = 1;
			else
				pic[i][j] = 0;
		}
		getchar();
	}
	ans = INF;
	dfs(0, 0, 0, 0);//不选 
	dfs(0, 0, 1, 1);//选 
	if(ans == INF)
		printf("Impossible\n");
	else
		printf("%d\n", ans);
}

更好

#include <stdio.h>

const int inf=9999999;
char s[10];
int map[10][10],i,j;
int ans=inf;
 
int panduan(){
    int x=map[0][0];
    for (i=0; i<4; i++){
        for (j=0; j<4; j++){
            if (map[i][j]!=x)
                return 0;
        }
    }
    return 1;
}
void fan (int x,int y){
    map[x][y]=!map[x][y];
    if (x - 1 >= 0)
        map[x-1][y]=!map[x-1][y];
    if (x + 1 < 4)
        map[x+1][y]=!map[x+1][y];
    if (y - 1 >= 0)
        map[x][y-1]=!map[x][y-1];
    if (y + 1 < 4)
        map[x][y+1]=!map[x][y+1];
}
int dfs (int x,int y,int t){
    if ( panduan()){
        if (ans > t)
            ans = t ;
        return 0;
    }
    if (x >= 4 || y >= 4)
        return 0;
    int nx,ny;
    nx = (x + 1)%4;
    ny = y + ( x + 1 ) / 4;
    dfs (nx,ny,t);
    fan (x,y);
    dfs (nx,ny,t+1);
    fan (x,y);
    return 0;
}
 
int main (){
    for (i=0; i<4; i++){
        scanf ("%s",s);
        for (j=0; j<4; j++){
            if (s[j]=='b')
                map[i][j]=0;
            else
                map[i][j]=1;
        }
    }
    dfs (0,0,0);
    if (ans == inf )
        printf ("Impossible\n");
    else printf ("%d\n",ans);
    return 0;
}

连通块问题
HDU - 2102

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;

char pic[2][12][12];
int vis[2][12][12];
int T;
int n, m, t;
int eh, er, ec;
int flag;
typedef struct node{
	int h, r, c, t;
}node;

int addr[4] = {1, -1, 0, 0};
int addc[4] = {0, 0, 1, -1};
bool check(int h, int r, int c){
	if(r >= n || r < 0 || c >= m || c < 0 || vis[h][r][c] || pic[h][r][c] == '*')	return true;
	return false;
}

void bfs(int h, int r, int c){
	node temp;
	temp.h = h, temp.r = r, temp.c = c, temp.t = 0;
	vis[0][0][0] = 1;
	queue<node> que;
	que.push(temp);
	while(!que.empty()){
		node tt = que.front();
		que.pop();
		if(tt.h == eh && tt.r == er && tt.c == ec){
			flag = 1;
			break;
		}
		if(tt.t >= t)//接下来的点一定不满足条件,跳过 
			continue;
		for(int i = 0; i < 4; ++ i){
			temp = tt;
			temp.r += addr[i];
			temp.c += addc[i];
			temp.t +=  1;
			if(check(temp.h, temp.r, temp.c))
				continue;
			vis[temp.h][temp.r][temp.c] = 1;
			if(pic[temp.h][temp.r][temp.c] == '#'){//'#'号的地方自动跳到不同楼层的相同位置 
				temp.h = !temp.h;
				if(check(temp.h, temp.r, temp.c) || pic[temp.h][temp.r][temp.c] == '#')
					continue;
				vis[temp.h][temp.r][temp.c] = 1;
			}
			if(temp.h == eh && temp.r == er && temp.c == ec){
				flag = 1;
				break;
			}
			que.push(temp);
		}
	}
}
int main(){
	scanf("%d\n", &T);
	while(T--){
		scanf("%d %d %d\n", &n, &m, &t);
		for(int i = 0; i < 2; ++ i){
			for(int j = 0; j < n; ++ j){
				for(int k = 0; k < m; ++ k){
					scanf("%c", &pic[i][j][k]);
					vis[i][j][k] = 0;
					if(pic[i][j][k] == 'P')
						eh = i, er = j, ec = k;
				}
				getchar();
			}
			if(i == 0)
				getchar();
		}
		flag = 0;
		bfs(0, 0, 0);
		if(flag)
			printf("YES\n");
		else
			printf("NO\n");
	}
}

FZU - 2150
连通块,染色问题

#include<cstdio>
#include<cstring>
#include<string>
#include<queue>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
int t, n, m;
char pic[12][12];
int vis[12][12];
int len[12][12];
int addx[4] = {1, -1, 0, 0};
int addy[4] = {0, 0, 1, -1};

typedef struct node{
	int num, x, y, t;
}node;
node d[105];
int cnt = 0;
void init(){
	for(int i = 0; i < n; ++ i)
		for(int j = 0; j < m; ++ j)
			vis[i][j] = 0;
}

bool check(int x, int y){
	if(x >= 0 && x < n && y >= 0 && y < m && pic[x][y] == '#')	return true;
	return false;
}

void bfs(int x, int y){
	init();
	queue<node> que;
	node pp;
	pp.x = x, pp.y = y, pp.t = 0;
	vis[x][y] = 1;
	len[x][y] = 0;
	que.push(pp);
	while(!que.empty()){
		node p = que.front();
		que.pop();
		for(int i = 0; i < 4; ++ i){
			pp = p;
			pp.x += addx[i];
			pp.y += addy[i];
			pp.t ++;
			if(check(pp.x, pp.y) && vis[pp.x][pp.y] == 0){
				len[pp.x][pp.y] = min(len[pp.x][pp.y], pp.t);
				vis[pp.x][pp.y] = 1;
				que.push(pp);
			}
		}
	}
}


int main(){
	int cc = 1;
	for(scanf("%d\n", &t); t; t--){
		scanf("%d %d\n", &n, &m);
		cnt = 0;
		for(int i = 0; i < n; ++ i){
			for(int j = 0; j < m; ++ j){
				scanf("%c", &pic[i][j]);
				if(pic[i][j] == '#')//用结构体存可以当起点的点,题目保证至少有一个 
					d[cnt].num = cnt, d[cnt].x = i, d[cnt ++].y = j;
			}	
			getchar();
		}
		int maxx = INF;
		for(int i = 0; i < cnt; ++ i){
			for(int j = i; j < cnt; ++ j){//暴力历遍所有选择两个点的可能 
				for(int k = 0; k < n; ++ k){
					for(int z = 0; z < m; ++ z)
						len[k][z] = INF;
				}
				bfs(d[i].x, d[i].y);
				bfs(d[j].x, d[j].y);
				int maxt = 0;
				for(int k = 0; k < cnt; ++ k){
					if(len[d[k].x][d[k].y] > maxt)
						maxt = len[d[k].x][d[k].y];//找出这次选择的最大花费时间 
				}
				maxx = min(maxt, maxx);//每次选择的最大花费时间中的最短时间 
			}
		}
		printf("Case %d: ", cc++);
		if(maxx == INF)
			printf("-1\n");
		else
			printf("%d\n", maxx);
	}
}

其他问题
poj - 1426

#include<cstdio>
#include<queue>
using namespace std;
typedef long long ll;//题目中说不超过100位, 但是实际上,200以内的数longlong 就够了,
						//不知道为什么 
int flag;
void bfs(ll x){
	queue<ll> que;
	que.push(1);
	while(!que.empty()){
		ll k = que.front();
		que.pop();
		if(k % x == 0){
			printf("%lld\n", k);
			break;
		}
		que.push(k*10);
		que.push(k*10+1);
	}
}
int n;
int main(){
	while(~scanf("%d", &n), n){
		flag = 0;
		bfs(n);
	}
}

正规做法//用字符串爆空间

#include<iostream>
using namespace std;

int mod[524286];  //保存每次mod n的余数
                  //由于198的余数序列是最长的
                  //经过反复二分验证,436905是能存储198余数序列的最少空间
                  //但POJ肯定又越界测试了...524286是AC的最低下限,不然铁定RE

int main(int i)
{
	int n;
	while(cin>>n)
	{
		if(!n)
			break;

		mod[1]=1%n;  //初始化,n倍数的最高位必是1

		for(i=2;mod[i-1]!=0;i++)  //利用同余模定理,从前一步的余数mod[i/2]得到下一步的余数mod[i]
			mod[i]=(mod[i/2]*10+i%2)%n;
		             //mod[i/2]*10+i%2模拟了BFS的双入口搜索
		             //当i为偶数时,+0,即取当前位数字为0  。为奇数时,则+1,即取当前位数字为1
					//模拟了01二叉数 
		i--;
		int pm=0;
		while(i)
		{
			mod[pm++]=i%2;   //把*10操作转化为%2操作,逆向求倍数的每一位数字
			i/=2;
		}
		while(pm)
			cout<<mod[--pm];  //倒序输出
		cout<<endl;
	}
	return 0;
}
posted @ 2020-07-19 16:58  wansheking  阅读(91)  评论(0)    收藏  举报