1:棋盘问题
在一个给定形状的棋盘(形状可能是不规则的)上面摆放棋子,棋子没有区别。要求摆放时任意的两个棋子不能放在棋盘中的同一行或者同一列,请编程求解对于给定形状和大小的棋盘,摆放k个棋子的所有可行的摆放方案C。
本题要注意任意两个棋子都不能放在棋盘中的同一列或者同一行,通过这句话我们可以将问题转化为从第一行开始,每行只放一个,并且与上面的棋子不在同一列,那么我们只要按照行或列每次遍历一行或者一列,然后DFS求出所有的可能。
假如按行遍历,我们就只需要标记哪一列被放过棋子。
这种题虽然简单但是按行搜索的方法却很巧妙
代码:
#include <stdio.h>
#include <iostream>
#include <string.h>
using namespace std;
#define fo(i,a,b) for(int i = a; i < b; i++) //宏定义 加快函数速度并简化函数写法
#define met(a,b) memset(a,0,sizeof(a));
char map[9][9];
int vis[9]; // 因为每次都是按行搜索,所以一定不在同一行,所以只需要标记列。
int n, m, sum, num;
void print(){ // 棋盘输入
met(map, 0);
met(vis, 0);
sum = 0, num = 0;
fo(i, 0, n)
fo(j, 0, n)
cin>>map[i][j];
}
void dfs(int x,int num){
if(num==m)
{
sum++;
return ; //当棋子全部放入棋盘后,返回最后一层的上一层;
}
fo(i, x, n)
fo(j, 0, n){
if(map[i][j]=='#'&&!vis[j]){
vis[j] = 1;
dfs(i+1,num+1); // 递归节点
vis[j] = 0; // 回溯节点
}
}
}
int main()
{
while(cin>>n>>m&&n!=-1&&m!=-1){
print();
dfs(0,0);
cout<<sum<<endl;
}
return 0;
}
2. Dungeon Master
普通的BFS只不过从二维变成了三维,也就是多了两个上下的方向,
#include <stdio.h>
#include <iostream>
#include <string>
#include <string.h>
#include <math.h>
#include <queue>
using namespace std;
#define met(a,b) memset(a,b,sizeof(a))
#define for(i,a,b) for(int i = a; i < b; i++)
struct node{
int x,y,z;
node(int x = 0, int y = 0, int z = 0):x(x), y(y), z(z){}
};
queue <node> q;
int vis[33][33][33];
int step[33][33][33];
char map[33][33][33];
int nex[6][3] = {{0, 1, 0}, {1, 0, 0}, {0, 0, 1}, {0, 0, -1}, {0, -1, 0}, {-1, 0, 0}};
int L, R, C, sx, sy, sz, count1;
void init(){ // 输入
met(vis, 0);
met(map, 0);
met(step, 0);
count1 = 0;
while(!q.empty()) q.pop();
for(l, 0, L)
for(i, 0, R)
for(j, 0, C){
cin>>map[i][j][l];
if(map[i][j][l] == 'S') {sx = i; sy = j, sz = l;}
}
}
void bfs(){
node a;
a.x = sx; a.y = sy; a.z = sz;
q.push(a);
while(!q.empty()){
node b = q.front();
q.pop();
for(i, 0, 6){
a.x = b.x + nex[i][0];
a.y = b.y + nex[i][1];
a.z = b.z + nex[i][2];
if((map[a.x][a.y][a.z] == '.' || map[a.x][a.y][a.z] == 'E') && !vis[a.x][a.y][a.z]){
vis[a.x][a.y][a.z] = 1;
step[a.x][a.y][a.z] = step[b.x][b.y][b.z] + 1;
if(map[a.x][a.y][a.z] == 'E'){count1 = 1; printf("Escaped in %d minute(s).\n",step[a.x][a.y][a.z]); return; }
q.push(a);
}
}
}
return ;
}
int main(){
while(cin>>L>>R>>C,L, R, C){
init();
bfs();
if(!count1) {cout<<"Trapped!"<<endl;}
}
return 0;
}
3.Catch That Cow
简单bfs
#include <stdio.h>
#include <iostream>
#include <string>
#include <string.h>
#include <queue>
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
struct node{
int x,step;
node(int x=0, int step=0):x(x), step(step){}
};
int N,K;
int vis[1000002];
void bfs(){
memset(vis, 0, sizeof(vis));
queue <node> q;
node a;
a.x = N;
a.step=0;
q.push(a);
vis[a.x] = 1;
while(!q.empty()){
node r = q.front();
q.pop();
for(int i = 0; i < 3; i++){
if(i==0){
a.x = r.x + 1;
if(!vis[a.x]&&a.x>=0&&a.x<=100000){
a.step=r.step+1,q.push(a),vis[a.x]=1;
if(a.x==K) {cout<<a.step<<endl;return;}
}
}
if(i==1){
a.x = r.x - 1;
if(!vis[a.x]&&a.x>=0&&a.x<=100000) {
a.step=r.step+1,q.push(a),vis[a.x]=1;
if(a.x==K) {cout<<a.step<<endl;return;}
}
}
if(i==2){
a.x = r.x * 2;
if(!vis[a.x]&&a.x>=0&&a.x<=100000){
a.step=r.step+1,q.push(a),vis[a.x]=1;
if(a.x==K) {cout<<a.step<<endl;return;}
}
}
}
}
return ;
}
int main(){
cin >> N >> K ;
if(N==K) cout<<"0"<<endl;
else bfs();
return 0;
}
4. Fliptile (开关问题+二进制搜索) 每一个位置的改变可以影响周围4个方向,如果按行或列来看的话,这一行以上就只有上一行能影响到下一行,可以简化问题,所以我们可以枚举出第一行所有的情况,然后从第二行开始,让第一行变白。然后直到最后一行,如果最后一行也是白色,则将反转情况的数组存起来,更新反转次数更小的,最后输出。
#include <iostream>
#include <string>
#include <cstring>
#include <queue>
using namespace std;
#define met(a,b) memset(a,b,sizeof(a))
#define fo(i,a,b) for(int i = a; i < b; i++)
int map[20][20];
int cal[20][20];
int Min[20][20];
int n,m;
int nxt[5][2] = {{0,0},{0,1},{0,-1},{1,0},{-1,0}};
int getc(int x,int y){ //(x,y)的状态由本身的黑白 + 周围五个的翻转状态决定
int t = map[x][y];
for(int i = 0;i < 5;i ++){
int nx = x + nxt[i][0];
int ny = y + nxt[i][1];
if(nx < 1 || nx > n || ny < 1 || ny > m) continue;
t += cal[nx][ny];
}
return t%2;
}
int dfs(){
for(int i = 2; i <= n; i++)
for(int j = 1;j <= m;j ++)
if(getc(i-1,j)) cal[i][j] = 1; //如果上方为黑色,必须要翻转
for(int i = 1; i <= m; i++) //最后一行全白
if(getc(n,i)) return -1;
int t = 0;
for(int i = 1;i <= n;i ++)
for(int j = 1;j <= m;j ++)
t += cal[i][j];
return t;
}
int main()
{
while(cin>>n>>m){
for(int i = 1;i <= n; i++)
for(int j = 1;j <= m; j++)
cin>>map[i][j];
int flag = 0, ans = -1;
for(int i = 0;i < 1<<m; i++){ //第一行 1<<m种状态,二进制从0开始,字典序从小到大
memset(cal,0,sizeof(cal));
for(int j = 1;j <= m; j++) //利用二进制枚举第一行所有的情况
cal[1][m-j+1] = i>>(j-1) & 1;
int cont = dfs();
if(cont >= 0 &&(cont < ans || ans<0)){ //翻转次数最少
flag = 1;
ans = cont;
memcpy(Min,cal,sizeof(cal));
}
}
if(!flag) cout<<"IMPOSSIBLE"<<endl;
else{
for(int i = 1;i <= n;i ++){
for(int j = 1;j <= m;j ++){
if(j != 1) cout<<" ";
cout<<Min[i][j];
}
cout<<endl;
}
}
}
return 0;
}
5.Find The Multiple
long long 可以存下最大答案,简单BFS
#include <stdio.h>
#include <string>
#include <iostream>
#include <string.h>
#include <queue>
using namespace std;
#define ll long long
int x;
void bfs(){
queue<ll> q;
q.push(1);
while(!q.empty()){
ll b = q.front();
q.pop();
if(b % x == 0) {cout<<b<<endl; return;}
for(int i = 0; i < 2; i++){
if(i == 0){ ll a = b*10 + 0; q.push(a);}
else { ll a = b*10 + 1; q.push(a);}
}
}
}
int main(){
while(cin>>x,x){
bfs();
}
return 0;
}
6.Prime Path
将一个数变为一个素数,每次改变一位,且改变后该数仍为素数。求最少操作次数,那BFS肯定是跑不掉了。
可以提前将所有四位数的素数打表,然后就可以直接查询了。
每次遍历某一位的所有情况,将所有符合条件的数加入队列。
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <queue>
#include <math.h>
#include <algorithm>
using namespace std;
#define met(a,b) memset(a,b,sizeof(a))
#define fo(i,a,b) for(int i = a; i < b; i++)
int vis[10000];
int A[10000]={0};
int x, y;
bool flag;
typedef pair <int, int> P;
bool sushu(int a){
for(int i = 2; i < a/2+1 ;i++)
if(a%i==0) return false;
return true;
}
void FindA(){
for(int i = 999; i<9999;i+=2){
if(sushu(i)){
A[i] = 1;
}
}
return ;
}
void solve(int sum,int &A, int &B, int &C, int &D){
D = sum / 1000;
C = sum /100 %10;
B = sum /10 %10;
A = sum %10;
return ;
}
void bfs(){
flag=false;
for(int i = 1000; i <= 9999; i+=1)
vis[i] = 0;
queue <P> q;
q.push(P(x,0));
vis[x] = 1;
while(!q.empty()){
P p = q.front();
q.pop();
int ONE,TEN,HUN,TND;
solve(p.first,ONE,TEN, HUN, TND);
if(p.first == y) {cout<<p.second<<endl; flag=true; return;}
//qian
for(int j = 1; j <= 9; j++){
P pp;
pp.first = j*1000 + HUN*100 + TEN*10 + ONE;
// if(pp.first==y) {cout << p.second+1 <<endl;flag=true;return;}
if(A[pp.first]&&!vis[pp.first]) {pp.second=p.second+1;q.push(pp);vis[pp.first]=1;}
}
//bai
for(int j = 0; j <= 9; j++){
P pp;
pp.first = TND*1000 + j*100 + TEN*10 + ONE;
// if(pp.first==y) {cout << p.second+1 <<endl;flag=true;return;}
if(A[pp.first]&&!vis[pp.first]) {pp.second=p.second+1;q.push(pp);vis[pp.first]=1;}
}
//shi
for(int j = 0; j <= 9; j++){
P pp;
pp.first = TND*1000 + HUN*100 + j*10 + ONE;
// if(pp.first==y) {cout << p.second+1 <<endl;flag=true;return;}
if(A[pp.first]&&!vis[pp.first]) {pp.second=p.second+1;q.push(pp);vis[pp.first]=1;}
}
//ge
for(int j = 0; j <= 9; j++){
P pp;
pp.first = TND*1000 + HUN*100 + TEN*10 + j;
// if(pp.first==y) {cout << p.second+1 <<endl;flag=true;return;}
if(A[pp.first]&&!vis[pp.first]) {pp.second=p.second+1;q.push(pp);vis[pp.first]=1;}
}
}
return ;
}
int main(){
int T;
FindA();
cin>>T;
while(T--)
{
cin>>x>>y;
bfs();
if(flag==false)
cout << "Impossible\n";
}
return 0;
}
7. Shuffle'm Up
牌的最底部是 S[0];
暴力模拟,然后把出现过的字符加入map数组中,如果有重复,则退出,输出 -1;
#include <cstdio>
#include <iostream>
#include <queue>
#include <string>
#include <map>
#include <set>
using namespace std;
int main(){
int T;
cin>>T;
for(int i = 0; i < T; i++){
map <string,int> S;
int m,cnt = 0;
cin>>m;
string s,s1,s2,s3=""; // s + s1 -> s2
cin>>s>>s1>>s2;
while(1){
s3="";
cnt++;
for(int i = 0; i < m; i++){
s3 =s3 + s1[i] + s[i];
}
if(S[s3]) {cnt = -1;break;}
if(s3==s2) {break;}
else{
S[s3] = 1;
s = s3.substr(0,m);
s1 = s3.substr(m,m);
}
}
cout<<i+1<<" "<<cnt<<endl;
}
return 0;
}
8.Pots
倒水问题,关键是将所有瓶中的水看做一个状态,然后模拟倒水就行了。
这个题还要存储一下上一次倒水的值,倒序查找路径,保存后倒序输出路径。
#include <stdio.h>
#include <string>
#include <iostream>
#include <queue>
#include <cstring>
using namespace std;
#define met(a,b) memset(a,b,sizeof(a))
#define fo(i,a,b) for(int i = a; i < b; i++)
struct node{
int a,b,step;
};
int vis[110][110];
node l[110][110];
int A,B,C,flag = 0;
node cnt;
void bfs(){
queue <node> q;
node nx;
nx.a = 0;
nx.b = 0;
nx.step = 0;
l[nx.a][nx.b].a = 0;
l[nx.a][nx.b].b = 0;
q.push(nx);
while(!q.empty()){
node r = q.front();
q.pop();
if(r.a==C||r.b==C) {flag = 1; cout<<r.step<<endl; cnt.a = r.a; cnt.b = r.b; return ;}
if(r.a!=A){ // 装满 A
nx.a = A;
nx.b = r.b;
if(!vis[nx.a][nx.b]){
vis[nx.a][nx.b] = 1;
l[nx.a][nx.b].a = r.a;
l[nx.a][nx.b].b = r.b;
nx.step = r.step + 1;
q.push(nx);
}
}
if(r.b!=B){ // 装满 B
nx.a = r.a;
nx.b = B;
if(!vis[nx.a][nx.b]){
vis[nx.a][nx.b] = 1;
l[nx.a][nx.b].a = r.a;
l[nx.a][nx.b].b = r.b;
nx.step = r.step + 1;
q.push(nx);
}
}
if(r.a){ // 倒掉 A
nx.a = 0;
nx.b = r.b;
if(!vis[nx.a][nx.b]){
vis[nx.a][nx.b] = 1;
l[nx.a][nx.b].a = r.a;
l[nx.a][nx.b].b = r.b;
nx.step = r.step + 1;
q.push(nx);
}
}
if(r.b){ // 倒掉 B
nx.b = 0;
nx.a = r.a;
if(!vis[nx.a][nx.b]){
vis[nx.a][nx.b] = 1;
l[nx.a][nx.b].a = r.a;
l[nx.a][nx.b].b = r.b;
nx.step = r.step + 1;
q.push(nx);
}
}
if(r.a&&r.b!=B){ // 将 A -> B
int x = r.a + r.b;
if(x<=B) {nx.b = x; nx.a = 0;}
else {nx.b = B; nx.a = x - B;}
if(!vis[nx.a][nx.b]){
vis[nx.a][nx.b] = 1;
l[nx.a][nx.b].a = r.a;
l[nx.a][nx.b].b = r.b;
nx.step = r.step + 1;
q.push(nx);
}
}
if(r.b&&r.a!=A){ // 将 B - > A
int x = r.a + r.b;
if(x<=A) {nx.a = x; nx.b = 0;}
else {nx.a = A; nx.b = x - A;}
if(!vis[nx.a][nx.b]){
vis[nx.a][nx.b] = 1;
l[nx.a][nx.b].a = r.a;
l[nx.a][nx.b].b = r.b;
nx.step = r.step + 1;
q.push(nx);
}
}
}
cout<<"impossible\n";
return ;
}
void print(){
if(flag){
node x[100000];
int i = cnt.a;
int j = cnt.b;
int k = 1;
x[0].a = i;
x[0].b = j;
while(i!=0||j!=0){
x[k].a = l[i][j].a;
x[k].b = l[i][j].b;
int t = i;
i = l[i][j].a;
j = l[t][j].b;
k++;
}
for(int i = k-1; i>0; i--){
// cout<<x[i].a<<" "<<x[i].b<<" "<<x[i-1].a<<" "<<x[i-1].b<<endl;
if(x[i-1].a-x[i].a==0&&x[i-1].b-x[i].b!=0){
if(x[i-1].b==B){
cout<<"FILL(2)\n";
}
else if(x[i-1].b==0)
cout<<"DROP(2)\n";
}
else if(x[i-1].a-x[i].a!=0&&x[i-1].b-x[i].b==0){
if(x[i-1].a==A){
cout<<"FILL(1)\n";
}
else if(x[i-1].a==0)
cout<<"DROP(1)\n";
}
else if(x[i-1].a-x[i].a!=0&&x[i-1].b-x[i].b!=0){
if(x[i-1].a-x[i].a>0&&x[i].b-x[i-1].b>0) // b -> a;
cout<<"POUR(2,1)\n";
else if(x[i].a-x[i-1].a>0&&x[i-1].b-x[i].b>0) // a - > b;
cout<<"POUR(1,2)\n";
}
}
}
}
int main(){
while(cin>>A>>B>>C){
flag = 0;
memset(vis,0,sizeof(vis));
memset(l,0,sizeof(l));
vis[0][0] = 1;
bfs();
print();
}
return 0;
}
9.Fire Game
判断能否把草烧完,输出最小时间, 有两个起始点,输入时把草的数量存起来,然后BFS,求出BFS中遍历到的草的数量,和总共的草的数量比较,如果不等于,则输出-1;
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <queue>
using namespace std;
#define met(a,b) memset(a,b,sizeof(a))
#define fo(i,a,b) for(int i = a; i < b; i++)
char map[15][15];
int vis[15][15];
int nxt[4][2] = {0,1,1,0,0,-1,-1,0};
int n,m;
struct node{
int x,y,step;
node(int x = 0,int y = 0, int step = 0):x(x),y(y),step(step){}
}Arr[100];
int k;
int minnt = 0;
void init(){
k = 0;
met(Arr,0);
fo(i,0,n){
fo(j,0,m)
{
cin>>map[i][j];
if(map[i][j] == '#'){ Arr[k].x = i; Arr[k].y = j; k++;}
}
}
}
int bfs(int x, int y, int x1, int y1){
met(vis,0);
vis[x][y] = 1;
vis[x1][y1] = 1;
int cnt = 0;
queue <node> q;
node nx, nx1;
nx.x = x; nx.y = y;
nx1.x = x1; nx1.y = y1;
q.push(nx);
q.push(nx1);
if(x==x1&&y==y1) cnt = 1;
else cnt = 2;
while(!q.empty()){
node r = q.front();
q.pop();
for(int i=0;i<4;i++){
nx.x = r.x + nxt[i][0];
nx.y = r.y + nxt[i][1];
if(nx.x<0||nx.x>=n||nx.y<0||nx.y>=m) continue;
if(!vis[nx.x][nx.y]&&map[nx.x][nx.y]=='#'){
vis[nx.x][nx.y] = 1;
nx.step = r.step + 1;
minnt = nx.step;
cnt++;
q.push(nx);
}
}
}
if(cnt == k){
return 1;
}
else return 0;
}
int main(){
int T,count = 0;
cin>>T;
while(T--){
count++;
cin>>n>>m;
init();
// fo(i,0,k) cout<<Arr[i].x<<" "<<Arr[i].y<<endl;
int minn = -1;
for(int i = 0; i < k; i++)
for(int j = i; j < k; j++){
if(bfs(Arr[i].x,Arr[i].y,Arr[j].x,Arr[j].y)&&(minn>minnt||minn==-1))
minn = minnt;
}
if(k<=2) minn = 0;
cout<<"Case "<<count<<": "<<minn<<endl;
}
return 0;
}
10.Fire!
先对火进行BFS,然后记录每个点火蔓延到的时间,然后对人进行BFS,BFS时判断人到某点的时间是否比火早,如果不比火早则不能通过。
#include <iostream>
#include <string.h>
#include <queue>
using namespace std;
#define fo(i,a,b) for(int i = a; i < b; i++)
#define met(a,b) memset(a,b,sizeof(a));
typedef struct Point{
int x,y;
Point(int x=0, int y=0):x(x),y(y){}
}Point;
int nex[4][2]={0, 1, 1, 0, 0, -1, -1, 0};
char map[1010][1010];
int vis[1010][1010];
int timef[1010][1010],timej[1010][1010];
int n, m, x, y, x1, y1;
queue <Point> q;
void Fbfs(){
met(vis, 0);
met(timef, 0);
while(!q.empty()){
Point a = q.front();
vis[a.x][a.y] = 1;
q.pop();
fo(i, 0, 4){
Point b;
b.x = a.x + nex[i][0];
b.y = a.y + nex[i][1];
if(map[b.x][b.y] =='.'&&!vis[b.x][b.y]&&b.x>=0&&b.x<n&&b.y>=0&&b.y<m){
vis[b.x][b.y] = 1;
timef[b.x][b.y] = timef[a.x][a.y] + 1; // 向外扩展的层数
q.push(b);
}
}
}
return;
}
int Jbfs(){
met(vis, 0);
met(timej, 0);
vis[x][y] = 1;
Point a;
a.x = x;
a.y = y;
q.push(a);
while(!q.empty()){
Point b = q.front();
q.pop();
fo(i, 0, 4){
a.x = b.x + nex[i][0];
a.y = b.y + nex[i][1];
if(a.x<0||a.y<0||a.x>=n||a.y>=m){
printf("%d\n",timej[b.x][b.y]+1);
return 0;
}
else if(map[a.x][a.y]=='.'&&(timef[a.x][a.y]>timej[b.x][b.y]+1||timef[a.x][a.y]==0)&&!vis[a.x][a.y]){
vis[a.x][a.y] = 1; //注意判断条件 (timef[a.x][a.y]>timej[b.x][b.y]+1||timef[a.x][a.y]==0) 火走不到或者人走到这一步时,火走不到
timej[a.x][a.y] = timej[b.x][b.y] + 1; // 向外扩展的层数
q.push(a);
}
}
}
printf("IMPOSSIBLE\n");
return 0;
}
void print()
{
while(!q.empty())
q.pop();
met(map, 0);
fo(i, 0, n){
fo(j, 0, m)
{
scanf("%c",&map[i][j]);
if(map[i][j]=='F'){
Point c;
c.x = i;
c.y = j;
q.push(c); //将所有火的坐标都进队,同时进行BFS向外层层扩展
}
if(map[i][j]=='J'){
x = i;
y = j;
}
}
getchar();
}
}
int main()
{
int T;
scanf("%d",&T);
while(T--){
scanf("%d %d", &n, &m);
getchar();
print();
Fbfs();
Jbfs();
}
return 0;
}
11.迷宫问题
简单BFS,但需要输出路径,正着搜索输出路径很麻烦,但这道题可以倒着搜索,会方便一点。
#include <iostream>
#include <string>
#include <string.h>
#include <queue>
using namespace std;
#define met(a,b) memset(a,0,sizeof(a))
#define fo(i,a,b) for(int i = a; i < b; i++)
int nex[4][2] = {-1,0,0,-1,0,1,1,0};
int map[5][5];
int vis[5][5];
struct node{
int x,y;
}n[5][5];
void init(){
met(vis, 0);
met(map, 0);
fo(i, 0, 5)
fo(j, 0, 5)
cin>>map[i][j];
}
void bfs(){
queue <node> q;
node a;
a.x = 4; a.y = 4;
q.push(a);
while(!q.empty()){
node b = q.front(); q.pop();
fo(i, 0, 4){
a.x = b.x + nex[i][0];
a.y = b.y + nex[i][1];
if(map[a.x][a.y]==0&&!vis[a.x][a.y]&&a.x>=0&&a.x<5&&a.y>=0&&a.y<5){
q.push(a);
vis[a.x][a.y] = 1;
n[a.x][a.y].x = b.x;
n[a.x][a.y].y = b.y;
}
if(a.x==0&&a.y==0) return;
}
}
}
int main()
{
init();
bfs();
int i = 0, j = 0;
while(1){
cout<<"("<<i<<", "<<j<<")"<<endl;
if(i==4&&j==4) return 0;
int ii = i;
i = n[i][j].x;
j = n[ii][j].y;
}
return 0;
}
12.DFS求连通块数量.
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <queue>
using namespace std;
char map[110][110];
int vis[110][110];
int nxt[8][2] = {{0,1},{1,1},{1,0},{1,-1},{0,-1},{-1,-1},{-1,0},{-1,1}};
int n,m;
void init(){
memset(vis,0,sizeof(vis));
memset(map,0,sizeof(map));
for(int i = 0; i < n; i++){
scanf("%s",map[i]);
getchar();
}
}
void dfs(int x, int y){
for(int i = 0; i < 8; i++){
int nx = x + nxt[i][0];
int ny = y + nxt[i][1];
if(!vis[nx][ny]&&nx>=0&&nx<n&&ny>=0&&ny<m){
vis[nx][ny] = 1;
if(map[nx][ny]=='@') dfs(nx, ny);
}
}
}
int main(){
while(cin>>n>>m,n,m){
getchar();
init();
int cnt = 0;
for(int i = 0; i < n; i++){
for(int j = 0; j < m; j++){
if(!vis[i][j]&&map[i][j]=='@'){
vis[i][j] = 1;
dfs(i,j);
cnt++;
}
}
}
cout<<cnt<<endl;
}
return 0;
}
13.非常可乐
倒水问题. 将三个瓶中水的体积作为一个状态,然后BFS模拟倒水。(倒水时只考虑两个瓶子)
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <queue>
using namespace std;
struct node{
int s,n,m,step;
};
int S,N,M;
int vis[105][105][105];
void bfs(){
memset(vis,0,sizeof(vis));
vis[S][0][0] = 1;
node s;
s.s = S; s.n = 0; s.m = 0; s.step = 0;
queue <node> q;
q.push(s);
while(!q.empty()){
node r = q.front();
q.pop();
if(r.s==S/2&&r.m==S/2){ cout<<r.step<<endl; return;}
if(r.s&&r.m!=M){ // s -> M;
int c = r.m + r.s;
if(c<=M) {s.s = 0; s.m = r.m + r.s; s.n = r.n;}
else {s.s = c - M; s.m = M; s.n = r.n;}
if(!vis[s.s][s.n][s.m])
{
s.step = r.step + 1;
vis[s.s][s.n][s.m] = 1;
q.push(s);
}
}
if(r.s&&r.n!=N){ // s -> N;
int c = r.n + r.s;
if(c<=N) {s.s = 0; s.n = r.n + r.s; s.m = r.m;}
else {s.s = c - N; s.n = N; s.m = r.m;}
if(!vis[s.s][s.n][s.m])
{
s.step = r.step + 1;
vis[s.s][s.n][s.m] = 1;
q.push(s);
}
}
if(r.n&&r.s!=S){ // N -> S ;
s.s = r.n+r.s; s.n = 0; s.m = r.m;
if(!vis[s.s][s.n][s.m])
{
s.step = r.step + 1;
vis[s.s][s.n][s.m] = 1;
q.push(s);
}
}
if(r.n&&r.m!=M){ // N - > M;
int c = r.m + r.n;
if(c<=M) {s.s = r.s; s.m = r.m + r.n; s.n = 0;}
else {s.s = r.s; s.m = M; s.n = c - M;}
if(!vis[s.s][s.n][s.m])
{
s.step = r.step + 1;
vis[s.s][s.n][s.m] = 1;
q.push(s);
}
}
if(r.m&&r.s!=S){ // M - > S
s.s = r.s + r.m; s.m = 0; s.n = r.n;
if(!vis[s.s][s.n][s.m])
{
s.step = r.step + 1;
vis[s.s][s.n][s.m] = 1;
q.push(s);
}
}
if(r.m&&r.n!=N){ //M - > N;
int c = r.m + r.n;
if(c<=N) {s.s = r.s; s.n = r.m + r.n; s.m = 0;}
else {s.s = r.s; s.n = N; s.m = c - N;}
if(!vis[s.s][s.n][s.m])
{
s.step = r.step + 1;
vis[s.s][s.n][s.m] = 1;
q.push(s);
}
}
}
cout<<"NO"<<endl;
return;
}
int main(){
while(scanf("%d%d%d",&S,&N,&M),S||N||M){
if(N>M){
int t = N;
N = M;
M = t;
}
if(S%2!=0){
cout<<"NO\n";
continue;
}
else
bfs();
}
return 0;
}
14.进行两次BFS,分别记录两个人到达KFC的时间,然后求出两个人到达同一个KFC的最小时间.
#include <stdio.h>
#include <iostream>
#include <queue>
#include <string>
#include <string.h>
using namespace std;
#define met(a,b) memset(a,b,sizeof(a))
#define for(i,a,b) for(int i=a;i<b;i++)
#define INF 1e9
struct Point{
int x,y;
Point(int x=0, int y=0):x(x),y(y){}
};
char map[202][202];
int vis[202][202];
int nex[4][2] = {0, 1, 1, 0, 0, -1, -1, 0};
int x,y,xx,yy,n,m;
int a[202][202];
int b[202][202];
queue <Point> q;
void print(){
met(map, 0);
met(vis, 0);
met(a, 0);
met(b, 0);
for(i, 0, n){
for(j, 0, m){
scanf("%c",&map[i][j]);
if(map[i][j] == 'Y')
x = i, y = j;
else if(map[i][j]=='M')
xx = i, yy = j;
}
getchar();
}
// for(i, 0, n)
// {
// for(j, 0, m)
// cout<<map[i][j];
// cout<<endl;
// }
}
void Bfs(int x,int y,int num[202][202]){
vis[x][y] = 1;
Point t;
t.x = x;
t.y = y;
q.push(t);
while(!q.empty()){
Point r = q.front();
q.pop();
for(i, 0, 4){
t.x = r.x + nex[i][0];
t.y = r.y + nex[i][1];
if(map[t.x][t.y] == '#'||t.x<0||t.x>=n||t.y<0||t.y>=m||vis[t.x][t.y])
continue;
else{
vis[t.x][t.y] = 1;
q.push(t);
num[t.x][t.y] = num[r.x][r.y] + 1;
}
}
}
}
void slove(){
int minn = INF;
for(i, 0, n)
{
for(j, 0, m){
if(map[i][j] == '@'&&a[i][j]!=0&&b[i][j]!=0)
minn = min(minn, a[i][j]+b[i][j]);
}
}
cout<<minn*11<<endl;
}
int main()
{
while(scanf("%d%d",&n,&m)!=EOF){
getchar();
print();
Bfs(x, y, a);
met(vis, 0);
Bfs(xx, yy, b);
slove();
}
return 0;
}