简单搜索总结--kuangbin带你飞专题一

今天网络赛又被虐了,哎,还是太菜,还是忘了吧,重要的是努力,是提升,黑暗总会过去的!!!希望一直都有,只要你肯坚持!从现在做起,重拾信心,重拾希望,不要企图一步登天,不要想那些虚无缥缈的未来,脚踏实地,向前进!

现在就把前阵子写的专题一做个总结吧。

bfs:递归实现,所以容易超时爆栈,而且判重、标记要么都在中间,要么都在开头(根据写法类型而定,“先判再走”or"走后再判")【见A题】。回溯恢复要么都在本层,要么都在下一层。【见A题】

如果题目要求最优解,找到目标后,每次还要进行比较取优。

如果题目中,每一步可以任意走的话,可以采用。

bfs:循环实现,不会爆栈。判重、标记要么都在入队前,要么都在出队后。

第一次找到目标后,就是最优解,无需比较取优。

如果题目中,每一步有规定,只能特定地走,可以采用。

可以打印路径,只要用数组模拟队列,并且在节点的结构体中加一个pre就行,路径的第一个节点的pre设为-1,打印时用一个递归函数,终止条件就是pre!=-1。

A题:

题意:

给你一个n*n的棋盘,棋盘上只有'#'位置可以放置棋子,要求放置k个棋子,棋子每一行,每一列只能有一个棋子。

思路:

由于n,k很小,不超过8,直接暴搜就行,看了一下自己的提交记录,发现并不是1A,任何的非1A都可能导致一场比赛的失败,这也暴露了自己对暴搜写法有一定的问题。

先看一下我的AC代码:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define Fin             freopen("in.txt","r",stdin)
#define Fout            freopen("out.txt","w",stdout)
#define Case(T)         int T;for(scanf("%d",&T);T--;)
#define fo(i,a,b)              for(int i = a; i < b; ++i)
#define fd(i,a,b)              for(int i = a; i >= b; --i)
#define me(a,b) memset(a,b,sizeof(a))
#define Scand(n)	   scanf("%d",&n);
#define Scans(s)	   scanf("%s",s);
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b ? gcd(b,a%b): a; }
ll inv(ll a,ll m) { if(a == 1) return 1; return inv(m%a,m)*(m-m/a)%m; }
int lowbit(int x) {	return x & (-x); }
const int maxn = 500000 + 100;
const int INF = 0xffffff;

#ifndef ONLINE_JUDGE

#endif // ONLINE_JUDGE

int n,k;
char mp[10][10];
int ans;

int vis1[10];
int vis2[10]; 

void dfs(int now, int cnt){
	if(cnt == k){
		ans++;
		return;
	}
	for(int i = now; i <= n; ++i){
		if(vis1[i])	continue;
		for(int j = 1; j <= n; ++j){
			if(vis2[j])	continue;
			if(mp[i][j] == '#'){
				vis1[i] = 1;
				vis2[j] = 1;
				dfs(i+1,cnt+1);
				vis1[i] = 0;
				vis2[j] = 0;
			}
		}
	}
}


int main()
{
	#ifndef ONLINE_JUDGE
		//Fin;
	#endif // ONLINE_JUDGE
	while(scanf("%d%d",&n,&k) == 2){
		getchar();
		if(n == -1 && k == -1)	break;
		fo(i,1,n+1){
			fo(j,1,n+1)
				scanf("%c",&mp[i][j]);
			getchar();
		}

		ans = 0;
		dfs(1,0);
		printf("%d\n",ans);
	}
	return 0;
}

我上面的AC代码就是典型的判断后再走。

再看一下我的失败代码:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define Fin             freopen("in.txt","r",stdin)
#define Fout            freopen("out.txt","w",stdout)
#define Case(T)         int T;for(scanf("%d",&T);T--;)
#define fo(i,a,b)              for(int i = a; i < b; ++i)
#define fd(i,a,b)              for(int i = a; i >= b; --i)
#define me(a,b) memset(a,b,sizeof(a))
#define Scand(n)	   scanf("%d",&n);
#define Scans(s)	   scanf("%s",s);
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b ? gcd(b,a%b): a; }
ll inv(ll a,ll m) { if(a == 1) return 1; return inv(m%a,m)*(m-m/a)%m; }
int lowbit(int x) {	return x & (-x); }
const int maxn = 500000 + 100;
const int INF = 0xffffff;

#ifndef ONLINE_JUDGE

#endif // ONLINE_JUDGE

int n,k;
char mp[10][10];
int ans;

int vis1[10];
int vis2[10]; 

void dfs(int now, int cnt){
	if(cnt == k){
		ans++;
		return;
	}
	if(vis1[now])	return;
	for(int i = now; i <= n; ++i){
		for(int j = 1; j <= n; ++j){
			if(vis2[j])	continue;
			if(mp[i][j] == '#'){
				vis1[i] = 1;
				vis2[j] = 1;
				dfs(now+1,cnt+1);
				vis1[i] = 0;
				vis2[j] = 0;
			}
		}
	}
}


int main()
{
	#ifndef ONLINE_JUDGE
		//Fin;
	#endif // ONLINE_JUDGE
	while(scanf("%d%d",&n,&k) == 2){
		getchar();
		if(n == -1 && k == -1)	break;
		fo(i,1,n+1){
			fo(j,1,n+1)
				scanf("%c",&mp[i][j]);
			getchar();
		}

		ans = 0;
		dfs(1,0);
		printf("%d\n",ans);
	}
	return 0;
}

不难发现失败代码与ac代码就差别在对vis1数组的判重的位置,这告诉我,既然选择“判断后再走”,就必须严格遵循“先判重,然后走”,不能又在开头再判重

另外,又参考了一下别人的代码:

#include
#include
#include
#include
using namespace std;
char a[10][10];
int ans=0;
int n,k;
int visit [10];
void bfs(int cnt,int x,int y)
{
    if(cnt==k) {
        ans++;
        return ;
    }
    visit[y]=1;
    for(int i=x+1;i

他的代码在恢复状态的写法与我不同(对visit数组),其实两种方法都可以,我的放在里面,就是等它回到原来这一层,再给恢复,而他的代码,则是在进入下一层再标记,然后在回到本层才恢复标记

 

B题:

题意:

给一个三维的迷宫,’#‘不能走,’.'表示可以走,'S'表示起点,'E'表示终点,求最短逃离时间,若不能逃离,输出“Trapped!”,否则输出“Escaped in x minute(s).”。

思路:对于每一步行走有限制的题目,一般采用bfs,而每一步可以任意行走的题,例如上一题,可以采用dfs,本次采用bfs,对六个方向进行试探,入队...

代码1(极其冗杂易错的代码):

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define Fin             freopen("in.txt","r",stdin)
#define Fout            freopen("out.txt","w",stdout)
#define Case(T)         int T;for(scanf("%d",&T);T--;)
#define fo(i,a,b)              for(int i = a; i < b; ++i)
#define fd(i,a,b)              for(int i = a; i >= b; --i)
#define me(a,b) memset(a,b,sizeof(a))
#define Scand(n)	   scanf("%d",&n);
#define Scans(s)	   scanf("%s",s);
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b ? gcd(b,a%b): a; }
ll inv(ll a,ll m) { if(a == 1) return 1; return inv(m%a,m)*(m-m/a)%m; }
int lowbit(int x) {	return x & (-x); }
const int maxn = 500000 + 100;
const int INF = 0xffffff;

#ifndef ONLINE_JUDGE

#endif // ONLINE_JUDGE

typedef struct Node{
	int x,y,z;
}Node;

typedef struct node{
	int step;
	Node loc;
}node;

int l,r,c;
char mp[100][100][100];
int vis[100][100][100];
Node start,end;
queue que;
int ans;


void bfs(){
	while(!que.empty())
		que.pop();
	me(vis,0);
	ans = 0;
	node Begin;
	Begin.step = 0;
	Begin.loc.x = start.x;
	Begin.loc.y = start.y;
	Begin.loc.z = start.z;
	que.push(Begin);
	vis[start.z][start.x][start.y] = 1;
	while(!que.empty()){
		node now = que.front();
		que.pop();
		int step = now.step; 
		int z = now.loc.z; int x = now.loc.x; int y = now.loc.y;
		//printf("now:  step:%d z:%d x:%d y:%d\n",step,z,x,y);
		if(z == end.z && x == end.x && y == end.y){
			//printf("success!! step:%d z:%d x:%d y:%d\n",step,z,x,y);
			ans = step;
			return;
		}
		//printf("上: vis:%d mp:%c\n",vis[z+1][x][y],mp[z+1][x][y]);
		if(z+1 <= l && !vis[z+1][x][y] && mp[z+1][x][y] != '#'){
			//printf("上: step:%d z:%d x:%d y:%d\n",step+1,z+1,x,y);
			node temp;
			temp.step = step+1;
			temp.loc.z = z+1;	temp.loc.x = x; temp.loc.y = y;
			vis[z+1][x][y] = 1;
			que.push(temp);
		}
		//printf("下: vis:%d mp:%c\n",vis[z-1][x][y],mp[z-1][x][y]);
		if(z-1 >= 1 && !vis[z-1][x][y] && mp[z-1][x][y] != '#'){
			//printf("下: step:%d z:%d x:%d y:%d\n",step+1,z-1,x,y);
			node temp;
			temp.step = step+1;
			temp.loc.z = z-1;	temp.loc.x = x; temp.loc.y = y;
			vis[z-1][x][y] = 1;
			que.push(temp);
		}
		//printf("右: vis:%d mp:%c\n",vis[z][x+1][y],mp[z][x+1][y]);
		if(x+1 <= r && !vis[z][x+1][y] && mp[z][x+1][y] != '#'){
			//printf("右: step:%d z:%d x:%d y:%d\n",step+1,z,x+1,y);
			node temp;
			temp.step = step+1;
			temp.loc.z = z;	temp.loc.x = x+1; temp.loc.y = y;
			vis[z][x+1][y] = 1;
			que.push(temp);
		}
		//printf("左: vis:%d mp:%c\n",vis[z][x-1][y],mp[z][x-1][y]);
		if(x-1 >= 1 && !vis[z][x-1][y] && mp[z][x-1][y] != '#'){
			//printf("左: step:%d z:%d x:%d y:%d\n",step+1,z,x-1,y);
			node temp;
			temp.step = step+1;
			temp.loc.z = z;	temp.loc.x = x-1; temp.loc.y = y;
			vis[z][x-1][y] = 1;
			que.push(temp);
		}
		//printf("前: vis:%d mp:%c\n",vis[z][x][y+1],mp[z][x][y+1]);
		if(y+1 <= c && !vis[z][x][y+1] && mp[z][x][y+1] != '#'){
			//printf("前: step:%d z:%d x:%d y:%d\n",step+1,z,x,y+1);
			node temp;
			temp.step = step+1;
			temp.loc.z = z;	temp.loc.x = x; temp.loc.y = y+1;
			vis[z][x][y+1] = 1;
			que.push(temp);
		}
		//printf("后: vis:%d mp:%c\n",vis[z][x][y-1],mp[z][x][y-1]);
		if(y-1 >= 1 && !vis[z][x][y-1] && mp[z][x][y-1] != '#'){
			//printf("后: step:%d z:%d x:%d y:%d\n",step+1,z,x,y-1);
			node temp;
			temp.step = step+1;
			temp.loc.z = z;	temp.loc.x = x; temp.loc.y = y-1;
			vis[z][x][y-1] = 1;
			que.push(temp);
		}
	}
}

int main()
{
	#ifndef ONLINE_JUDGE
		Fin;
	#endif // ONLINE_JUDGE
	while(scanf("%d%d%d",&l,&r,&c) == 3){
		//printf("l:%d r:%d c:%d\n",l,r,c);
		//getchar();
		if(!l && !r && !c)	break;
		me(mp,0);
		int i,j,k;
		for(i = 1; i <= l; ++i){
			for(j = 1; j <= r; ++j){
				scanf("%s",mp[i][j]+1);
				for(k = 1; k <= c; ++k){
					if(mp[i][j][k] == 'S'){
						start.x = j; start.y= k; start.z = i;
					}
					if(mp[i][j][k] == 'E'){
						end.x = j; end.y= k; end.z = i;
					}
				}
				//getchar();
			}
			//getchar();
		}
		/*for(int i = 1; i <= l; ++i){
			for(int j = 1; j <= r; ++j){
				for(int k = 1; k <= c; ++k){
					cout << mp[i][j][k];
				}
				cout << endl;
			}
			cout << endl;
		}
		printf("start: x:%d y:%d z:%d\n",start.x, start.y, start.z);
		printf("end: x:%d y:%d z:%d\n",end.x, end.y, end.z);*/
		ans = 0;
		bfs();
		if(ans == 0)
			cout << "Trapped!" << endl;
		else
			printf("Escaped in %d minute(s).\n",ans);
	}
	return 0;
}

其实上面的bfs的代码量可以缩短很多的,首先可以写一个check函数,判断点是否合理,另外,六个方向可以用三个一维数组(1*6)表示。

代码2(简洁代码,其中的六个方向的表示,代码中提供了两种方法,个人喜欢没被注释掉的那种方法):

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define Fin             freopen("in.txt","r",stdin)
#define Fout            freopen("out.txt","w",stdout)
#define Case(T)         int T;for(scanf("%d",&T);T--;)
#define fo(i,a,b)              for(int i = a; i < b; ++i)
#define fd(i,a,b)              for(int i = a; i >= b; --i)
#define me(a,b) memset(a,b,sizeof(a))
#define Scand(n)	   scanf("%d",&n);
#define Scans(s)	   scanf("%s",s);
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b ? gcd(b,a%b): a; }
ll inv(ll a,ll m) { if(a == 1) return 1; return inv(m%a,m)*(m-m/a)%m; }
int lowbit(int x) {	return x & (-x); }
const int maxn = 500000 + 100;
const int INF = 0xffffff;

#ifndef ONLINE_JUDGE

#endif // ONLINE_JUDGE

int l,r,c;
char mp[35][35][35];
int vis[35][35][35];
//int dire[6][3] = {{0,0,1},{0,0,-1},{1,0,0},{-1,0,0},{0,1,0},{0,-1,0}};
int dirx[] = {0,0,1,-1,0,0};
int diry[] = {0,0,0,0,1,-1};
int dirz[] = {1,-1,0,0,0,0};
int stx,sty,stz,edx,edy,edz;

struct node{
	int x,y,z;
	int step;
};
queue que;

void Init(){
	while(!que.empty())
		que.pop();
	me(vis,0); 
} 

int check(node temp){
	if(!(1 <= temp.z && temp.z <= l))	return 0;
	if(!(1 <= temp.x && temp.x <= r))	return 0;
	if(!(1 <= temp.y && temp.y <= c))	return 0;
	if(vis[temp.x][temp.y][temp.z])	return 0;
	if(mp[temp.z][temp.x][temp.y] == '#')	return 0;
	return 1;
}

int dfs(){
	Init();
	node startt;
	startt.x = stx, startt.y = sty, startt.z = stz;	startt.step = 0;
	que.push(startt);
	vis[stx][sty][stz] = 1;
	while(!que.empty()){
		node now = que.front();
		que.pop();
		int x = now.x; int y = now.y; int z = now.z; int step = now.step;
		if(x == edx && y == edy && z == edz){
			return step;
		}
		fo(i,0,6){
			node nextt = now;
			//nextt.x += dire[i][0];
			//nextt.y += dire[i][1];
			//nextt.z += dire[i][2];
                          nextt.x += dirx[i]; nextt.y += diry[i]; nextt.z += dirz[i];
			nextt.step++; 
			if(check(nextt)){
				que.push(nextt);
				vis[nextt.x][nextt.y][nextt.z] = 1;
			} 
		}
	}
	return 0;
}

int main()
{
	#ifndef ONLINE_JUDGE
		Fin;
	#endif // ONLINE_JUDGE
	while(cin >> l >> r >> c){
		if(!l && !r && !c)	break;
		me(mp,0);
		fo(i,1,l+1){
			fo(j,1,r+1){
				scanf("%s",mp[i][j]+1);
				fo(k,1,c+1){
					if(mp[i][j][k] == 'S'){
						stx = j; sty = k; stz = i;
					}
					if(mp[i][j][k] == 'E'){
						edx = j; edy = k; edz = i;
					}
				}
			}		
		}
		
		int ans = dfs();
		if(ans)
			printf("Escaped in %d minute(s).\n",ans);
		else
			printf("Trapped!\n");
	}
	return 0;
}

C题

题意:

在一个一维空间里,给你一个初始位置,以及一个目标位置,你有三种方式可以走,1是左移一个单位,2是右移一个单位,3是位置扩为两倍,要求位置在[0,1e5]之间。问到达目标位置最少需要多少步?

思路:

限定了每步只可有三种选择,那么选择dfs,再注意一下边界就行。

代码:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define Fin             freopen("in.txt","r",stdin)
#define Fout            freopen("out.txt","w",stdout)
#define Case(T)         int T;for(scanf("%d",&T);T--;)
#define fo(i,a,b)              for(int i = a; i < b; ++i)
#define fd(i,a,b)              for(int i = a; i >= b; --i)
#define me(a,b) memset(a,b,sizeof(a))
#define Scand(n)	   scanf("%d",&n);
#define Scans(s)	   scanf("%s",s);
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b ? gcd(b,a%b): a; }
ll inv(ll a,ll m) { if(a == 1) return 1; return inv(m%a,m)*(m-m/a)%m; }
int lowbit(int x) {	return x & (-x); }
const int maxn = 100000 + 100;
const int INF = 0xffffff;

#ifndef ONLINE_JUDGE

#endif // ONLINE_JUDGE

struct Node{
	int step,loc;
	Node(int a, int b){
		step = a;
		loc = b;
	}
};

int n,k;
int vis[maxn];
queue que;
int ans;

int check(int loc){
	if(!(0 <= loc && loc <= maxn))	return 0;
	if(vis[loc])	return 0;
	return 1;
}

void bfs(){
	Node start(0,n);
	if(n == k)
		return;
	que.push(start);
	vis[n] = 1;
	while(!que.empty()){
		Node now = que.front();
		que.pop();
		int step = now.step;  int loc = now.loc;
		//printf("step:%d loc:%d\n",step,loc);
		if(loc == k){
			ans = step;
			return ;
		}
		if(check(loc-1)){
			Node Next(step+1,loc-1);
			que.push(Next);
			//printf("loc:%d step:%d\n",Next.loc,Next.step);
			vis[loc-1] = 1;
		}
		if(check(loc+1)){
			Node Next(step+1,loc+1);
			que.push(Next);
			vis[loc+1] = 1;
		}
		if(check(loc*2)){
			Node Next(step+1,loc*2);
			que.push(Next);
			vis[loc*2] = 1;
		}
	}
} 

int main()
{
	#ifndef ONLINE_JUDGE
		//Fin;
	#endif // ONLINE_JUDGE
	cin >> n >> k;
	ans = 0;
	bfs();
	cout << ans << endl;
	return 0;
}

D题:

题意:

给N*M的01矩阵,对每一个位置,可以进行01翻转,翻转的同时,它的上下左右的四个位置也同时进行01翻转。问最少需要多少次翻转,可以使矩阵全0,输出每个位置的翻转次数。

思路:

首先,明确一点,每一个位置翻转2次,将回到原状态,翻转3次,等同于翻转1次,因而每个位置最多翻转1次

另外,对于这种翻转问题,而且是对周围的格子有影响的翻转,一般并不需要确定全部格子,只需确定一部分格子,剩下的格子在确定好了的格子的影响下,也将被确定。而对于本题,你只要确定第一行的格子,那么第二行也就确定了(第二行的分布方式得需将第一行变为全0,就是说第一行的第i列为1时,相应的第二行的第i列要翻转一次),同理,第二行确定后,第三行受第二行的约束,也将确定......所以只要枚举第一行就行,可以采用dfs,暴力枚举第一行,对于第一行的每一个位置,进行01试探。

代码:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define Fin             freopen("in.txt","r",stdin)
#define Fout            freopen("out.txt","w",stdout)
#define Case(T)         int T;for(scanf("%d",&T);T--;)
#define fo(i,a,b)              for(int i = a; i < b; ++i)
#define fd(i,a,b)              for(int i = a; i >= b; --i)
#define me(a,b) memset(a,b,sizeof(a))
#define Scand(n)       scanf("%d",&n);
#define Scans(s)       scanf("%s",s);
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b ? gcd(b,a%b): a; }
const int maxn = 110000 + 5;
const int INF = 0xffffff;

#ifndef ONLINE_JUDGE

#endif // ONLINE_JUDGE

int mp[20][20];
int temp[20][20];
int ans[20][20];
int answer[20][20];
int cnt;
int m,n;
int flag;

void flip(int x, int y){
    if(x-1 >= 1)
        temp[x-1][y] = !temp[x-1][y];
    if(x+1 <= m)
        temp[x+1][y] = !temp[x+1][y];
    if(y-1 >= 1)
        temp[x][y-1] = !temp[x][y-1];
    if(y+1 <= n)
        temp[x][y+1] = !temp[x][y+1];
    temp[x][y] = !temp[x][y];
}


int Count(){
    int sum = 0;
    fo(i,1,m+1)
        fo(j,1,n+1)
            if(ans[i][j] == 1)
                sum++;
                return sum;
}

void Copy(){
    fo(i,1,m+1)
        fo(j,1,n+1)
            answer[i][j] = ans[i][j];
}

int check(){
    for(int i = 1; i <= m; ++i){
        for(int j = 1;j <= n; ++j)
            temp[i][j] = mp[i][j];
    }
    fo(i,1,m+1){
        fo(j,1,n+1){
            if(ans[i][j] == 1)
                flip(i,j);
        }
        if(i != m){
            fo(j,1,n+1)
                ans[i+1][j] = temp[i][j];
        }
    }
    fo(i,1,m+1){
        fo(j,1,n+1){
            if(temp[i][j] == 1)
                return 0;
        }
    }
    return  1;
}


void dfs(int y){
    if(y == n){
        ans[1][y] = 0;
        if(check()){
            flag = 1;
            int num = Count();
            if(num < cnt){
                Copy();
                cnt = num;
            }
            return;
        }
        ans[1][y] = 1;
        if(check()){
            int num = Count();
            flag = 1;
            if(num < cnt){
                Copy();
                cnt = num;
            }
        }
        return;
    }
    ans[1][y] = 0;
    dfs(y+1);
    ans[1][y] = 1;
    dfs(y+1);
}

int main()
{
#ifndef ONLINE_JUDGE
    Fin;
#endif // ONLINE_JUDGE
    cin >> m >> n;
    fo(i,1,m+1)
        fo(j,1,n+1)
            cin >> mp[i][j];
    me(ans,0);
    flag = 0;
    cnt = INF;
    dfs(1);
    if(flag == 0)
        cout << "IMPOSSIBLE" << endl;
    else{
        print2();
    }
    return 0;
}

E题:

题意:

给你一个数n,要求输出一个n的倍数m,其中m是只有0和1的十进制数。

思路:

这题的n是不超过200,而m不超过100位,也就是10^(100),当时看了就慌了,这个m没法用任何类型来存啊。。太大了啊。。。后来想想,n不超过200,那么相应的m应该也不会达到100位吧,就用long long试试,然后就过了。。。

由于m只有0和1,那么对于m的每一位进行01试探就行。DFS和BFS都行吧。

我用的bfs(双端口bfs),另外,本题是special judge,也就是可能存在多解,输出一个就行,所以输出结果和样例不同也没事

代码:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define Fin             freopen("in.txt","r",stdin)
#define Fout            freopen("out.txt","w",stdout)
#define Case(T)         int T;for(scanf("%d",&T);T--;)
#define fo(i,a,b)              for(int i = a; i < b; ++i)
#define fd(i,a,b)              for(int i = a; i >= b; --i)
#define me(a,b) memset(a,b,sizeof(a))
#define Scand(n)       scanf("%d",&n);
#define Scans(s)       scanf("%s",s);
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b ? gcd(b,a%b): a; }
const int maxn = 110000 + 5;
const int INF = 0xffffff;

#ifndef ONLINE_JUDGE

#endif // ONLINE_JUDGE

queue que;
ll n;

void bfs(){
    while(!que.empty())
        que.pop();
    que.push(1);
    while (!que.empty()) {
        ll  temp = que.front();
        que.pop();
        if(temp%n == 0){
            cout << temp << endl;
            return;
        }
        que.push(temp*10);
        que.push(temp*10+1);
    }
}

int main()
{
#ifndef ONLINE_JUDGE
    //Fin;
#endif // ONLINE_JUDGE
    while(cin >> n){
        if(!n)  break;
        //printf("n:%lld\n",n);
        bfs();
    }
    return 0;

F题:

题意:

有a,b两个质数,要求通过一些转换,使a变为b,每次变换,只能变换一位,而且变换后的数也得是质数,问最少变换几次,可以得到b。a,b都是四位数。

思路:

由于只有四位数,然后每次只能改变一位数,那么采用bfs,可以对每一位的数依次尝试0~9,一共36种尝试,如果改变一位数后是质数,就入队,直到找到b。

注意点:

由于要对每一位进行改变,所以采用字符数组来存数字,方便对每一位进行操作,然后还得把字符数组表示的数字转化为数字,来判断是否是质数。所以要写一个字符数组的函数:

int chartonum(char s[]){
    int num = 0;
    for(int i = 0; i < 4; ++i){        //一个数字的越前位,越大,所以正向处理
        num = num*10 + (s[i]-'0');
    }
    return num;
}

代码:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define Fin             freopen("in.txt","r",stdin)
#define Fout            freopen("out.txt","w",stdout)
#define Case(T)         int T;for(scanf("%d",&T);T--;)
#define fo(i,a,b)              for(int i = a; i < b; ++i)
#define fd(i,a,b)              for(int i = a; i >= b; --i)
#define me(a,b) memset(a,b,sizeof(a))
#define fi(a,n,val)    fill(a,a+n,val)
#define Scand(n)       scanf("%d",&n)
#define Scans(s)       scanf("%s",s)
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b ? gcd(b,a%b): a; }
const int maxn = 110000 + 5;
const int INF = 0xffffff;

#ifndef ONLINE_JUDGE

#endif // ONLINE_JUDGE

int n;
char st[5],ed[5];
int ans;
bool notprime[10005];
int vis[10005];

struct node{
    int num;
    char numm[5];
    int step;
};

void Init(){
    memset(notprime, false, sizeof(notprime));
    notprime[0] = notprime[1] = true;
    for(int i = 2; i < 10005; ++i){
        if(!notprime[i]){
            if(i > 10005/i) continue;
            for(int j = i*i; j < 10005; j +=i)
                notprime[j] = true;
        }
    }
}

int chartonum(char s[]){
    int num = 0;
    for(int i = 0; i < 4; ++i){
        num = num*10 + (s[i]-'0');
    }
    return num;
}

void bfs(){
    queue que;
    node startt;
    strcpy(startt.numm, st);
    startt.num = chartonum(st);
    startt.step = 0;
    que.push(startt);
    vis[startt.num] = 1;
    while (!que.empty()) {
        node now = que.front();
        if(strcmp(now.numm, ed) == 0){
            ans = min(ans, now.step);
            return;
        }
        que.pop();
//        printf("now: num:%d step:%d\n",now.num,now.step);
        for(int i = 0; i < 4; ++i){
            char temp[5];
            strcpy(temp, now.numm);
//            printf("i:%d temp:%s\n",i,temp);
            for(int j = 0; j < 10; ++j){
                temp[i] = '0'+j;
//                printf("j:%d temp[%d]:%c\n",j,i,temp[i]);
                if(strcmp(temp, now.numm) == 0)
                    continue;
                int tempnum = chartonum(temp);
                if(notprime[tempnum])   continue;
                if(tempnum < 1000 || tempnum > 9999)    continue;
                if(vis[tempnum])    continue;
                node nextt;
                strcpy(nextt.numm, temp);
                nextt.num = chartonum(nextt.numm);
                nextt.step = now.step+1;
                que.push(nextt);
                vis[nextt.num] = 1;
//                printf("success\n");
            }
        }
    }
}


int main()
{
#ifndef ONLINE_JUDGE
    //Fin;
#endif // ONLINE_JUDGE
    Init();
    int n;
    Scand(n);
    fo(i, 0, n){
        me(st, 0);  me(ed, 0);
        Scans(st); Scans(ed);
//        printf("st:%s\ned:%s\n",st,ed);
        ans = INF;
        me(vis, 0);
        bfs();
        printf("%d\n",ans);
    }
    return 0;
}

G题:

题意:

类似于洗牌,给你两个字符串s1,s2,将s1,s2交叉插入,形成一个新字符串s,问能否得到给定的字符串。

思路:

由于整个过程都是固定唯一的,可以直接模拟这个过程,每次操作完,判断是否达到要求就行。其实就是一个递归函数,算不上dfs,好吧好吧,其实dfs不就是暴力递归吗。。。不过有一个问题就是,既然是递归,那么总得有一个终止条件吧,手算发现,经过一定次数的操作之后,s1,s2会回到一开始的s1,s2,那么以此作为终止条件就行。

技巧:

将s分割为s1和s2时,采用了strncpy函数。strncpy(字符数组名称,起始位置,切割长度)

代码:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define Fin             freopen("in.txt","r",stdin)
#define Fout            freopen("out.txt","w",stdout)
#define Case(T)         int T;for(scanf("%d",&T);T--;)
#define fo(i,a,b)              for(int i = a; i < b; ++i)
#define fd(i,a,b)              for(int i = a; i >= b; --i)
#define me(a,b) memset(a,b,sizeof(a))
#define fi(a,n,val)    fill(a,a+n,val)
#define Scand(n)       scanf("%d",&n)
#define Scand2(a,b)     scanf("%d%d",&a,&b)
#define Scand3(a,b,c)     scanf("%d%d%d",&a,&b,&c)
#define Scand4(a,b,c,d)     scanf("%d%d%d%d",&a,&b,&c,&d)
#define Scans(s)       scanf("%s",s)
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b ? gcd(b,a%b): a; }
const int maxn = 1e2 + 50;
const int INF = 0xffffff;

#ifndef ONLINE_JUDGE

#endif // ONLINE_JUDGE

char a[maxn], b[maxn], c[2*maxn], together[2*maxn];
int success,cnt;

void fun(char a[], char b[]){
    int len = strlen(a);
    char temp[maxn*2];
    int ind = 0;
    for(int i = 0; i < len; ++i)
        together[ind++] = b[i], together[ind++] = a[i];
//    printf("temp:%s\n",temp);
//    return temp;
}

void dfs(char x[], char y[]){
//    printf("before:x:%s\ny:%s\n",x,y);
//    printf("a:%s\nb:%s\nc:%s\n",a,b,c);
    if(strcmp(x, a) == 0 && strcmp(y, b) == 0 && cnt){
        return;
    }
//    char* together;
    fi(together, maxn-5, 0);
    fun(x, y);
    cnt++;
//    printf("together:%s\n",together);
    if(strcmp(together, c) == 0){
        success = 1;
        return;
    }
    int len = strlen(together);
    strncpy(x, together, len/2);    strncpy(y, together+len/2, len/2);
//    printf("after:x:%s\ny:%s\n",x,y);
    dfs(x, y);
}

int main()
{
#ifndef ONLINE_JUDGE
    //Fin;
#endif // ONLINE_JUDGE
    int T;
    Scand(T);
    for(int i = 1; i <= T; ++i){
        fi(a, maxn-5, 0);   fi(b, maxn-5, 0);   fi(c, maxn-5, 0);   fi(together, maxn-5, 0);
        int n;
        Scand(n);
        Scans(a), Scans(b), Scans(c);
        success = 0, cnt = 0;
//        printf("a:%s\nb:%s\nc:%s\n",a,b,c);
        char aa[maxn],bb[maxn];
        strcpy(aa, a);  strcpy(bb, b);
        dfs(aa,bb);
        if(success){
            printf("%d %d\n",i,cnt);
        }else{
            printf("%d %d\n",i,-1);
        }
    }
    return 0;
}

H题:

题意:

给你两个容器,分别能装下A升水和B升水,并且可以进行以下操作

FILL(i)        将第i个容器从水龙头里装满(1 ≤ i ≤ 2);

DROP(i)        将第i个容器抽干

POUR(i,j)      将第i个容器里的水倒入第j个容器(这次操作结束后产生两种结果,一是第j个容器倒满并且第i个容器依旧有剩余,二是第i个容器里的水全部倒入j中,第i个容器为空)

现在要求你写一个程序,来找出能使其中任何一个容器里的水恰好有C升,找出最少操作数并给出操作过程

思路:

在结构体中设置两个变量来表示两个瓶子中当前的水量。用bfs来遍历所有的可能,每一步有三种可能的操作。

另外由于要输出路径,所以要用数组模拟队列,并在结构体中设置了pre,路径中的第一个节点,也就是第一个入队的节点,将其的pre设为-1,之后入队的节点的pre设为父节点的数组下标。最后用递归函数打印路径,递归的终止条件是pre==-1。

还有就是由于选择第一种操作两种可能,所以进入循环前,要先push两个节点,也就是双入口bfs。

代码:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define Fin             freopen("in.txt","r",stdin)
#define Fout            freopen("out.txt","w",stdout)
#define Case(T)         int T;for(scanf("%d",&T);T--;)
#define fo(i,a,b)              for(int i = a; i < b; ++i)
#define fd(i,a,b)              for(int i = a; i >= b; --i)
#define me(a,b) memset(a,b,sizeof(a))
#define fi(a,n,val)    fill(a,a+n,val)
#define Scand(n)       scanf("%d",&n)
#define Scand2(a,b)     scanf("%d%d",&a,&b)
#define Scand3(a,b,c)     scanf("%d%d%d",&a,&b,&c)
#define Scand4(a,b,c,d)     scanf("%d%d%d%d",&a,&b,&c,&d)
#define Scans(s)       scanf("%s",s)
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b ? gcd(b,a%b): a; }
const int maxn = 1e6 + 50;
const int INF = 0xffffff;

#ifndef ONLINE_JUDGE

#endif // ONLINE_JUDGE

struct node{
    int id,order;
    int step,resultt1,resultt2;
    int pre;
};

node que[maxn];
int a,b,c;
int cnt = 0;
int success;
int vis[1000][1000];

void print(int num){
    if(num == -1){
        return;
    }
    print(que[num].pre);
    if(que[num].order == 1){
        printf("FILL(%d)\n",que[num].id);
    }
    else if(que[num].order == 2){
        printf("DROP(%d)\n",que[num].id);
    }else if(que[num].order == 3){
        printf("POUR(%d,%d)\n",que[num].id,3-que[num].id);
    }
}

void bfs(){
    me(que, 0); me(vis, 0); success = 0;
    node startt;
    startt.order = 1;   startt.id = 1; startt.pre = -1; startt.step = 1;    startt.resultt1 = a; startt.resultt2 = 0;
    int front = 0, rear = 0;
    que[rear++] = startt;
    startt.id = 2;  startt.resultt2 = b;    startt.resultt1 = 0;
    que[rear++] = startt;
    vis[0][0] = 1;
    int flag = 0;
    while (front < rear) {
        node now = que[front];
        if(now.resultt1 == c || now.resultt2 == c){
            success = 1;
            printf("%d\n",now.step);
            print(front);
            return ;
        }
        if(vis[now.resultt1][now.resultt2]){
            front++;
            continue;
        }
        vis[now.resultt1][now.resultt2] = 1;
            if(now.resultt1 != a){
                node nextt;
                nextt.id = 1; nextt.order = 1; nextt.pre = front; nextt.resultt1 = a; nextt.step = now.step+1; nextt.resultt2 = now.resultt2;
                que[rear++] = nextt;
            }
            if(now.resultt1 != 0){
                node nextt;
                nextt.id = 1; nextt.order = 2; nextt.pre = front; nextt.resultt1 = 0; nextt.step = now.step+1; nextt.resultt2 = now.resultt2;
                que[rear++] = nextt;
            }
            if(now.resultt1 != 0){
                node nextt;
                nextt.id = 1; nextt.order = 3; nextt.pre = front; nextt.step = now.step+1;
                if(now.resultt1+now.resultt2 > b){
                    nextt.resultt2 = b;
                    nextt.resultt1 = now.resultt1-(b-now.resultt2);
                }else{
                    nextt.resultt2 = now.resultt1+now.resultt2;
                    nextt.resultt1 = 0;
                }
                que[rear++] = nextt;
            }
            if(now.resultt2 != b){
                node nextt;
                nextt.id = 2; nextt.order = 1; nextt.pre = front; nextt.resultt2 = b; nextt.step = now.step+1; nextt.resultt1 = now.resultt1;
                que[rear++] = nextt;
            }
            if(now.resultt2 != 0){
                node nextt;
                nextt.id = 2; nextt.order = 2; nextt.pre = front; nextt.resultt2 = 0; nextt.step = now.step+1;  nextt.resultt1 = now.resultt1;
                que[rear++] = nextt;
            }
            if(now.resultt2 != 0){
                node nextt;
                nextt.id = 2; nextt.order = 3; nextt.pre = front;   nextt.step = now.step+1;
                if(now.resultt1+now.resultt2 > a){
                    nextt.resultt1 = a;
                    nextt.resultt2 = now.resultt2-(a-now.resultt1);
                }else{
                    nextt.resultt1 = now.resultt1+now.resultt2;
                    nextt.resultt2 = 0;
                }
                que[rear++] = nextt;
            }
        front++;
    }
}

int main()
{
#ifndef ONLINE_JUDGE
    //Fin;
#endif // ONLINE_JUDGE
    while(Scand3(a, b, c) == 3){
        bfs();
        if(!success)
            printf("impossible\n");
    }
    return 0;
}

I题:

题意:

两个熊孩子在n*m的平地上放火玩,#表示草,两个熊孩子分别选一个#格子点火,火可以向上向下向左向右在有草的格子蔓延,点火的地方时间为0,蔓延至下一格的时间依次加一。求烧完所有的草需要的最少时间。如不能烧完输出-1。

思路:

思路很简单,这题明显是双入口的bfs。先把可以烧的位置存进来,然后一个二重循环,遍历bfs 两个入口的位置,找出最优解就行。(这里要比较取优的原因在于,要进行多个bfs,每一个bfs求得的是最优解,然后在这些个最优解中取优)。

代码:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define Fin             freopen("in.txt","r",stdin)
#define Fout            freopen("out.txt","w",stdout)
#define Case(T)         int T;for(scanf("%d",&T);T--;)
#define fo(i,a,b)              for(int i = a; i < b; ++i)
#define fd(i,a,b)              for(int i = a; i >= b; --i)
#define me(a,b) memset(a,b,sizeof(a))
#define fi(a,n,val)    fill(a,a+n,val)
#define Scand(n)       scanf("%d",&n)
#define Scand2(a,b)     scanf("%d%d",&a,&b)
#define Scand3(a,b,c)     scanf("%d%d%d",&a,&b,&c)
#define Scand4(a,b,c,d)     scanf("%d%d%d%d",&a,&b,&c,&d)
#define Scans(s)       scanf("%s",s)
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b ? gcd(b,a%b): a; }
const int maxn = 1e4 + 50;
const int INF = 0xffffff;

#ifndef ONLINE_JUDGE

#endif // ONLINE_JUDGE

struct node{
    int x,y,step;
};

int n,m;
char mp[100][100];
int vis[100][100];
int ans, sum;
queue que;
vector  v;

int dirx[] = {1,-1,0,0};
int diry[] = {0,0,1,-1};


void bfs(int x1, int y1, int x2, int y2){
    me(vis, 0);
    ans = 0;
    while (!que.empty()) {
        que.pop();
    }
    node startt;
    startt.x = x1; startt.y = y1; startt.step = 0;
    que.push(startt);
    vis[x1][y1] = 1;
    startt.x = x2; startt.y = y2; startt.step = 0;
    que.push(startt);
    vis[x2][y2] = 1;
    while (!que.empty()) {
        node now = que.front();
        que.pop();
        int xx = now.x; int yy = now.y; int stepp = now.step;
        ans = stepp;
        //        int flag = 0;
        for(int i = 0; i < 4; ++i){
            int xxx = xx + dirx[i]; int yyy = yy + diry[i];
            if(!(0 <= xxx && xxx < n) || !(0 <= yyy && yyy < m))
                continue;
            node nextt;
            nextt.x = xxx; nextt.y = yyy; nextt.step = stepp+1;
            if(mp[xxx][yyy] == '#' && !vis[xxx][yyy]){
                que.push(nextt);
                vis[xxx][yyy] = 1;
            }
        }
    }
}

int judge(){
    fo(i, 0, n)
    fo(j, 0, m)
    if(mp[i][j] == '#' && !vis[i][j])
        return 0;
    return 1;
}

int main()
{
#ifndef ONLINE_JUDGE
     //Fin;
#endif // ONLINE_JUDGE
    int T;
    while(Scand(T) != EOF){
        for(int t = 1; t <= T; ++t){
            Scand2(n, m);
            me(mp, 0);  me(vis, 0);
            for(int i = 0; i < n; ++i)
                Scans(mp[i]);
            sum = 0;
            v.clear();
            for(int i = 0; i < n; ++i){
                for(int j = 0; j < m; ++j){
                    if(mp[i][j] == '#'){
                        sum++;
                        node temp;
                        temp.x = i; temp.y = j; temp.step = 0;
                        v.push_back(temp);
                    }
                }
            }
            int result = INF;
            for(int i=0;i

K题:

题意:

定义一个二维数组: 

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表示可以走的路,只能横着走或竖着走,不能斜着走,要求编程序找出从左上角到右下角的最短路线。

思路:

很简单的bfs迷宫问题,由于要打印路径,得模拟队列+pre标记

代码:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define Fin             freopen("in.txt","r",stdin)
#define Fout            freopen("out.txt","w",stdout)
#define Case(T)         int T;for(scanf("%d",&T);T--;)
#define fo(i,a,b)              for(int i = a; i < b; ++i)
#define fd(i,a,b)              for(int i = a; i >= b; --i)
#define me(a,b) memset(a,b,sizeof(a))
#define Scand(n)	   scanf("%d",&n);
#define Scans(s)	   scanf("%s",s);
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b ? gcd(b,a%b): a; }
ll inv(ll a,ll m) { if(a == 1) return 1; return inv(m%a,m)*(m-m/a)%m; }
int lowbit(int x) {	return x & (-x); }
const int maxn = 500000 + 100;
const int INF = 0xffffff;

#ifndef ONLINE_JUDGE

#endif // ONLINE_JUDGE
struct node{
	int x,y;
	int pre;
}que[100];

int mp[10][10];
int vis[10][10];
int dirx[] = {0,0,1,-1};
int diry[] = {1,-1,0,0};

int check(int x, int y){
	if(!(0 <= x && x <= 4))	return 0;
	if(!(0 <= y && y <= 4))	return 0; 
	if(mp[x][y] == 1)	return 0;
	if(vis[x][y])	return 0;
	return 1;
}

void print(int ind){
	if(que[ind].pre != -1){
		print(que[ind].pre);
		printf("(%d, %d)\n",que[ind].x,que[ind].y);
	}
}

void bfs(){
	int front = 0, rear = 0;
	que[rear].x = 0; que[rear].y = 0; que[rear].pre = -1;
	rear++;
	while(front < rear){
		node now = que[front];
		int x = now.x; int y = now.y;
		//printf("now: x:%d y:%d\n",x,y);
		if(x == 4 && y == 4){
			//printf("front:%d\n",front); 
			print(front);
			return ;
		}
		fo(i,0,4){
			if(check(x+dirx[i],y+diry[i])){
				que[rear].x = x+dirx[i];
				que[rear].y = y+diry[i];
				que[rear].pre = front;
				//printf("next: x:%d y:%d\n",que[rear].x,que[rear].y);
				rear++;
			}	
		}
		front++;
	}
}


int main()
{
	#ifndef ONLINE_JUDGE
		Fin;
	#endif // ONLINE_JUDGE
	me(mp,0);	me(vis,0);
	fo(i,0,5)
		fo(j,0,5)
			cin >> mp[i][j];
	cout << "(0, 0)" << endl;
	bfs();
	return 0;
}

L题:

题意:

给你一个字符矩阵,’*‘表示没油,’@‘表示有油,求图中油田的个数。

思路:

其实就是求连通块个数,直接用dfs搜一遍就行(遍历字符数组的每一个位置,如果是'@’,油田个数加一,再dfs其连通的'@',并做上标记)

代码:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define Fin             freopen("in.txt","r",stdin)
#define Fout            freopen("out.txt","w",stdout)
#define Case(T)         int T;for(scanf("%d",&T);T--;)
#define fo(i,a,b)              for(int i = a; i < b; ++i)
#define fd(i,a,b)              for(int i = a; i >= b; --i)
#define me(a,b) memset(a,b,sizeof(a))
#define Scand(n)	   scanf("%d",&n);
#define Scans(s)	   scanf("%s",s);
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b ? gcd(b,a%b): a; }
const int maxn = 100 + 5;
const int INF = 0xffffff;

#ifndef ONLINE_JUDGE

#endif // ONLINE_JUDGE

int n,m;
char mp[maxn][maxn];
int vis[maxn][maxn];
int cnt;

int check(int x, int y){
	if(!(0 <= x && x <= m-1))	return 0;
	if(!(0 <= y && y <= n-1))	return 0;
	if(mp[x][y] != '@' || vis[x][y])	return 0;
	return 1;
} 

void dfs(int x, int y){
	for(int i = -1; i <= 1; ++i){
		for(int j = -1; j <= 1; ++j){
			if(!i && !j)	continue;
			if(check(x+i,y+j)){
				vis[x+i][y+j] = 1;
				dfs(x+i,y+j);
			}
		}
	}
} 

int main()
{
	#ifndef ONLINE_JUDGE
		Fin;
	#endif // ONLINE_JUDGE
	while(cin >> m >> n){
		getchar();
		//printf("m:%d n:%d\n",m,n);
		if(!n && !m)	break;
		me(mp,0);
		fo(i,0,m){
			scanf("%s",mp[i]);
			//printf("i:%s\n",mp[i]);	
		}
		/*fo(i,0,m){
			fo(j,0,n)
				cout << mp[i][j];
			cout << endl; 
		}*/
		cnt = 0; me(vis,0);
		fo(i,0,m)
			fo(j,0,n){
				if(mp[i][j] == '@' && !vis[i][j]){
					//printf("i:%d j:%d\n",i,j);
					cnt++;
					vis[i][j] = 1;
					dfs(i,j);
				} 
			}
		cout << cnt << endl;
	}
	return 0;
}

M题:

题意:

只有两个杯子,它们的容量分别是N 毫升和M 毫升 可乐的体积为S (S<101)毫升 (正好装满一瓶) ,它们三个之间可以相互倒可乐 (都是没有刻度的,且 S==N+M,101>S>0,N>0,M>0) 。问两个人喝能平分吗?如果能请输出倒可乐的最少的次数,如果不能输出"NO"。

思路:

和H题一样的题,只不过这里是3个容器,所以结构体需要三个变量分别记录三个容器剩下的可乐。这里不需要打印,不需要模拟队列,直接用STL中的queue就行。

代码:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define Fin             freopen("in.txt","r",stdin)
#define Fout            freopen("out.txt","w",stdout)
#define Case(T)         int T;for(scanf("%d",&T);T--;)
#define fo(i,a,b)              for(int i = a; i < b; ++i)
#define fd(i,a,b)              for(int i = a; i >= b; --i)
#define me(a,b) memset(a,b,sizeof(a))
#define fi(a,n,val)    fill(a,a+n,val)
#define Scand(n)       scanf("%d",&n)
#define Scand2(a,b)     scanf("%d%d",&a,&b)
#define Scand3(a,b,c)     scanf("%d%d%d",&a,&b,&c)
#define Scand4(a,b,c,d)     scanf("%d%d%d%d",&a,&b,&c,&d)
#define Scans(s)       scanf("%s",s)
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b ? gcd(b,a%b): a; }
const int maxn = 1e4 + 50;
const int INF = 0xffffff;

#ifndef ONLINE_JUDGE

#endif // ONLINE_JUDGE

struct node{
    int a,b,c;
    int step;
    node(int aa = 0, int bb = 0, int cc = 0, int stepp = 0){
        a = aa; b = bb; c = cc; step = stepp;
    }
};

int s,n,m;
queue que;
int vis[200][200][200];
int ans;

void bfs(){
    while (!que.empty()) {
        que.pop();
    }
    fo(i, 0, 100)
        fo(j, 0, 100)
            fo(k, 0, 100)
                vis[i][j][k] = 0;
    node startt(s, 0, 0, 0);
    que.push(startt);
    while (!que.empty()) {
        node now = que.front();
        que.pop();
        int a = now.a; int b = now.b; int c = now.c; int step = now.step;
        if(vis[a][b][c])    continue;
        vis[a][b][c] = 1;
//        printf("a:%d b:%d c:%d step:%d\n",a,b,c,step);
        if((!a && b == c) || (!b && a == c) || (!c && a == b)){
            ans = step;
            return;
        }
        if(a > 0){
            if(a+b > n){
                node nextt(a+b-n, n, c, step+1);
                que.push(nextt);
            }else if(a+b < n){
                node nextt(0, a+b, c, step+1);
                que.push(nextt);
            }
            
            if(a+c > m){
                node nextt(a+c-m, b, m, step+1);
                que.push(nextt);
            }else if(a+c < m){
                node nextt(0, b, a+c, step+1);
                que.push(nextt);
            }
        }
        if(b > 0){
            if(b+a > s){
                node nextt(s, b+a-s, c, step+1);
                que.push(nextt);
            }else if(b+a < s){
                node nextt(b+a, 0, c, step+1);
                que.push(nextt);
            }
            
            if(b+c > m){
                node nextt(a, b+c-m, m, step+1);
                que.push(nextt);
            }else if(b+c < m){
                node nextt(a, 0, b+c, step+1);
                que.push(nextt);
            }
        }
        if(c > 0){
            if(c+a > s){
                node nextt(s, b, c+a-s, step+1);
                que.push(nextt);
            }else if(c < s){
                node nextt(c+a, b, 0, step+1);
                que.push(nextt);
            }
            
            if(c+b > n){
                node nextt(a, n, c+b-n, step+1);
                que.push(nextt);
            }else if(c+b < n){
                node nextt(a, c+b, 0, step+1);
                que.push(nextt);
            }
        }
    }
}

int main()
{
#ifndef ONLINE_JUDGE
    //Fin;
#endif // ONLINE_JUDGE
    while (Scand3(s, n, m) == 3) {
        if(!s && !n && !m)  break;
        ans = 0;
        bfs();
        if(ans == 0)
            printf("NO\n");
        else
            printf("%d\n",ans);
    }
    return 0;
}

N题:

题意:

一张图,上面有'@',两个人约定到其中的一个'@'中见面,求两人见面所花的最短时间。

思路:

可以求出两个人到达每一个'@'所花的时间,用两次bfs就行,然后对于每个'@',统计两人花费的时间(即两人分别所花时间相加),取最小值就行。

注意点:

bfs的终止条件是遍历完所有的'@',所以事先要记录图中'@'的个数

代码:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define Fin             freopen("in.txt","r",stdin)
#define Fout            freopen("out.txt","w",stdout)
#define Case(T)         int T;for(scanf("%d",&T);T--;)
#define fo(i,a,b)              for(int i = a; i < b; ++i)
#define fd(i,a,b)              for(int i = a; i >= b; --i)
#define me(a,b) memset(a,b,sizeof(a))
#define Scand(n)	   scanf("%d",&n);
#define Scans(s)	   scanf("%s",s);
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b ? gcd(b,a%b): a; }
const int maxn = 110000 + 5;
const int INF = 0xffffff;

#ifndef ONLINE_JUDGE

#endif // ONLINE_JUDGE

struct node{
    int x,y;
    int step;
    node(int a, int b, int c){
        x = a; y = b; step = c;
    }
};

int n,m;
char mp[250][250];
int vis1[250][250]; int vis2[250][250];
queue que;
int stx1,sty1,stx2,sty2;
int cnt,num;
int dirx[] = {0,0,1,-1};
int diry[] = {1,-1,0,0};

int check(int x, int y){
    if(!(1 <= x && x <= n)) return 0;
    if(!(1 <= y && y <= m)) return 0;
    if(mp[x][y] == '#' || mp[x][y] == 'Y' || mp[x][y] == 'M')	return 0;
    return 1;
}

void bfs1(){
    num = 0;
    while(!que.empty())
        que.pop();
    node startt(stx1,sty1,0);
    vis1[stx1][sty1] = 0;
    que.push(startt);
    while(!que.empty()){
        node now = que.front();
        que.pop();
        int x = now.x; int y = now.y; int step = now.step;
        if(mp[x][y] == '@'){
            num++;
            if(num == cnt)
                return;
        }
        fo(i,0,4){
            int xx = x + dirx[i];
            int yy = y + diry[i];
            if(check(xx,yy) && !vis1[xx][yy]){
                node nextt(xx,yy,step+1);
                vis1[xx][yy] = step+1;
                que.push(nextt);
            }
        }
    }
}

void bfs2(){
    num = 0;
    while(!que.empty())
        que.pop();
    node startt(stx2,sty2,0);
    vis1[stx2][sty2] = 0;
    que.push(startt);
    while(!que.empty()){
        node now = que.front();
        que.pop();
        int x = now.x; int y = now.y; int step = now.step;
        if(mp[x][y] == '@'){
            num++;
            if(num == cnt)
                return;
        }
        fo(i,0,4){
            int xx = x + dirx[i];
            int yy = y + diry[i];
            if(check(xx,yy) && !vis2[xx][yy]){
                node nextt(xx,yy,step+1);
                vis2[xx][yy] = step+1;
                que.push(nextt);
            }
        }
    }
}

int main()
{
	while(cin >> n >> m){
        me(mp,0);	me(vis1,0); 	me(vis2,0);
        cnt = 0;
        fo(i,1,n+1){
            scanf("%s",mp[i]+1);
            fo(j,1,m+1){
                if(mp[i][j] == 'Y'){
                    stx1 = i; sty1 = j;
                }
                if(mp[i][j] == 'M'){
                    stx2 = i; sty2 = j;
                }
                if(mp[i][j] == '@')
                    cnt++;
            }
        }
        bfs1();
        bfs2();
        int ans = INF;
        fo(i,1,n+1){
            fo(j,1,m+1){
                if(mp[i][j] == '@'){
                	if(!vis1[i][j] || !vis2[i][j])
                		continue;
                    ans = min(ans,vis1[i][j]+vis2[i][j]);
                }
            }
        }
        cout << ans*11 << endl;
    }
	return 0;
}

 

你可能感兴趣的:(acm,kuangbin专题)