菜鸟就要老老实实重新学起:
简单搜索:
一些简单搜索题,其中一些源自kuangbin大神的题目列表,留下以后出题用。
eg:
POJ1321 棋盘问题
http://poj.org/problem?id=1321
题意:
在一个棋盘内放k个棋子,每一行每一列都最多只能有一个棋子,求方法数,‘#’为可放的地方。思路:
直接暴力深搜枚举所有情况即可,每一行选择一个点向下继续深搜,同时a[]储存该列是否已有棋子。code:
#define N 11
int n,m;
int flag,sum,ave,ans,res,len,ans1,ans2;
int a[N];
int g[N][N];
char s[101];
void dfs(int now,int step)
{
if(step==m)
{
sum++;
return;
}
if(now==n)
return;
for(int i=0;i<n;i++)
if(g[now][i]&&!a[i])
{
a[i]=1;
dfs(now+1,step+1);
a[i]=0;
}
dfs(now+1,step);
}
int main()
{
int i,j,k,kk,t,x,y,z;
while(scanf("%d%d",&n,&m)!=EOF&&n!=-1)
{
memset(g,0,sizeof(g));
memset(a,0,sizeof(a));
for(i=0;i<n;i++)
{
scanf("%s",s);
x=strlen(s);
for(j=0;j<x;j++)
if(s[j]=='#')
g[i][j]=1;
}
sum=0;
dfs(0,0);
printf("%d\n",sum);
}
return 0;
}
POJ2251 Dungeon Master
http://poj.org/problem?id=2251
题意:
三维空间,求从S点到E点的最小距离。思路:
简单bfs搜索,从起点开始压入队列逐渐广搜开直到找到E或者队列为空,注意标记走过的位置。code:
#define N 112
int n,m,r,xx,yy,zz;
int flag,sum,ave,ans,res,len,ans1,ans2;
int g[N][N][N];
int dir[6][3]={1,0,0,-1,0,0,0,1,0,0,-1,0,0,0,1,0,0,-1};
char s[N];
struct node
{
int x,y,z,step;
}tn;
int bfs(int x,int y,int z)
{
queue<node> q;
while(!q.empty())q.pop();
node a,b;
a.x=x;a.y=y;a.z=z;a.step=0;
q.push(a);
while(!q.empty())
{
a=q.front();q.pop();
if(a.x==xx&&a.y==yy&&a.z==zz)
return a.step;
for(int i=0;i<6;i++)
{
b.x=a.x+dir[i][0];b.y=a.y+dir[i][1];b.z=a.z+dir[i][2];
if(b.x>=n||b.x<0||b.y>=m||b.y<0||b.z>=r||b.z<0)
continue;
if(g[b.z][b.x][b.y])
{
g[b.z][b.x][b.y]=0;
b.step=a.step+1;
q.push(b);
}
}
}
return -1;
}
int main()
{
int i,j,k,kk,t,x,y,z;
while(scanf("%d%d%d",&r,&n,&m)!=EOF&&n)
{
memset(g,0,sizeof(g));
for(k=0;k<r;k++)
for(i=0;i<n;i++)
{
scanf("%s",s);
int len=strlen(s);
for(j=0;j<len;j++)
{
if(s[j]=='#')
continue;
g[k][i][j]=1;
if(s[j]=='S')
x=i,y=j,z=k;
if(s[j]=='E')
xx=i,yy=j,zz=k;
}
}
t=bfs(x,y,z);
if(t==-1)
printf("Trapped!\n");
else
printf("Escaped in %d minute(s).\n",t);
}
return 0;
}
POJ3278 Catch That Cow
http://poj.org/problem?id=3278
题意:
求从第一个数变换到第二个数的最小步骤,数字每一步都可以加减1或者扩大2倍。思路:
暴力bfs搜索,状态有加一、减一、乘二,三种。code:#define N 212345
int n,m;
int flag,sum,ave,ans,res,len,ans1,ans2;
bool vis[N];
struct node
{
int x,y;
}tn;
int main()
{
queue<node> q;
node g,h;
int i,j,k,kk,t,x,y,z;
while(scanf("%d%d",&n,&m)!=EOF)
{
while(!q.empty())q.pop();
memset(vis,false,sizeof(vis));
g.x=n;g.y=0;vis[n]=true;
res=INF;
q.push(g);
while(res==INF&&!q.empty())
{
g=q.front();q.pop();
if(g.x==m)res=g.y;
h.x=g.x+1;h.y=g.y+1;
if(h.x<N&&!vis[h.x])
vis[h.x]=true,q.push(h);
h.x=g.x-1;
if(h.x>=0&&!vis[h.x])
vis[h.x]=true,q.push(h);
h.x=g.x*2;
if(h.x<N&&!vis[h.x])
vis[h.x]=true,q.push(h);
}
printf("%d\n",res);
}
return 0;
}
#define N 212345
int n,m;
int flag,sum,ave,ans,res,len,ans1,ans2;
bool vis[N];
struct node
{
int x,y;
}tn;
int main()
{
queue<node> q;
node g,h;
int i,j,k,kk,t,x,y,z;
while(scanf("%d%d",&n,&m)!=EOF)
{
while(!q.empty())q.pop();
memset(vis,false,sizeof(vis));
g.x=n;g.y=0;vis[n]=true;
res=INF;
q.push(g);
while(res==INF&&!q.empty())
{
g=q.front();q.pop();
if(g.x==m)res=g.y;
h.x=g.x+1;h.y=g.y+1;
if(h.x<N&&!vis[h.x])
vis[h.x]=true,q.push(h);
h.x=g.x-1;
if(h.x>=0&&!vis[h.x])
vis[h.x]=true,q.push(h);
h.x=g.x*2;
if(h.x<N&&!vis[h.x])
vis[h.x]=true,q.push(h);
}
printf("%d\n",res);
}
return 0;
}
POJ3279 Fliptile
http://poj.org/problem?id=3279
题意:
给出一些板子的正反状态,一头牛踩这些板子,每次踩下去之后被踩的板子和周围的四个都会翻转,求一种踩板子的方式能够使得所有板子都‘0’朝上。思路:
暴力枚举第一行的所有可能方案,之后向下搜索得出该方案是否可行。
因为每次变换的都是一个十字形区域,所以枚举得出第一行的状态后,可以得出当前第一行每个板子的状态,由此可以决定第二行对应板子的状态,由此不断向下搜索直到最后一行时判断是否都为0。第一行的枚举可以用状态压缩。
code:
#define N 20
int n,m;
int flag,sum,ave,res,len,ans1,ans2;
int f[N][N];
int ans[N][N];
int g[N][N];
bool mark(int x,int y)
{
return f[x-1][y]^f[x+1][y]^f[x][y-1]^f[x][y+1]^f[x][y]^g[x][y];
}
int main()
{
int i,j,k,kk,t,x,y,z;
while(scanf("%d%d",&n,&m)!=EOF)
{
memset(g,0,sizeof(g));
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
scanf("%d",&g[i][j]);
for(k=0;k<(1<<m);k++)
{
memset(f,0,sizeof(f));
for(i=1;i<=m;i++)
f[1][i]=k&(1<<(i-1))?1:0;
for(i=1;i<n;i++)
for(j=1;j<=m;j++)
f[i+1][j]=mark(i,j)?1:0;
flag=1;
for(i=1;i<=m;i++)
if(mark(n,i))
flag=0;
if(flag)
break;
}
if(!flag)
{
printf("IMPOSSIBLE\n");
continue;
}
for(i=1;i<=n;i++)
{
for(j=1;j<=m;j++)
printf("%d ",f[i][j]);
printf("\n");
}
}
return 0;
}
POJ1426 Find The Multiple
http://poj.org/problem?id=1426
题意:
寻找一个只包含1和0的十进制数是n的倍数。思路:
因为这个倍数的每一位都只有1或0两种状态,所以可以从首位开始向后bfs每种状态展开成末尾加1或0两种状态,直到得出结果。code:
#define N 1123
int n,m;
int flag,sum,ave,ans,res,len,ans1,ans2;
bool vis[N];
struct node
{
int now;
string s;
}tn;
int main()
{
int i,j,k,kk,t,x,y,z;
queue<node> q;
node a,b,c;
while(scanf("%d",&n)!=EOF&&n)
{
while(!q.empty())q.pop();
memset(vis,false,sizeof(vis));
a.now=1;a.s="1";vis[1]=true;
q.push(a);
while(!q.empty())
{
a=q.front();q.pop();
b.s=a.s+"1";c.s=a.s+"0";
b.now=(a.now*10+1)%n;c.now=(a.now*10)%n;
if(!b.now)
{
cout<<b.s<<endl;
break;
}
if(!c.now)
{
cout<<c.s<<endl;
break;
}
if(!vis[b.now])
{
vis[b.now]=true;
q.push(b);
}
if(!vis[c.now])
{
vis[c.now]=true;
q.push(c);
}
}
}
return 0;
}
POJ3126 Prime Path
http://poj.org/problem?id=3126
题意:
要求从第一个四位数变成第二个四位数字,每次只能改变某一位的数字,且每次改变之后的四位数必须是质数,求最少变换步骤,思路:
只有四位数而且求最少,直接暴力BFS,筛素数打表出四位数的所有素数判断,之后从第一个数字开始bfs,每次展开成4种状态,改变其中一位,同时判断是否为素数,直到得出结果。code:
#define N 11234
int n,m;
int flag,sum,ave,ans,res,len,ans1,ans2;
bool vis[N];
struct node
{
int x,y,z;
}tn;
bool mark[N];
int pri[N],cnt;
void SP()
{
cnt=0;
memset(mark,true,sizeof(mark));
mark[0]=mark[1]=false;
for(int i=2;i<N;i++)
{
if(mark[i])
pri[cnt++]=i;
for (int j=0;(j<cnt)&&(i*pri[j]<N);j++)
{
mark[i*pri[j]]=false;
if (i%pri[j]==0)
break;
}
}
}
int main()
{
int i,j,k,kk,t,x,y,z,w,now;
SP();
scanf("%d",&k);
while(k--)
{
scanf("%d %d",&n,&m);
memset(vis,false,sizeof(vis));
queue<node> q;
while(!q.empty())q.pop();
node g,h;
g.x=n;g.y=0;
q.push(g);
flag=0;
vis[n]=true;
while(!q.empty())
{
g=q.front();q.pop();
if(g.x==m)
{
flag=1;
res=g.y;
break;
}
x=g.x/1000;y=g.x/100%10;z=g.x/10%10;w=g.x%10;
t=g.x-x*1000;
for(i=1;i<=9;i++)
{
now=t+i*1000;
if(now!=g.x&&!vis[now]&&mark[now])
{
vis[now]=true;
h.x=now;h.y=g.y+1;h.z=g.x;
q.push(h);
}
}
t=g.x-y*100;
for(i=0;i<=9;i++)
{
now=t+i*100;
if(now!=g.x&&!vis[now]&&mark[now])
{
vis[now]=true;
h.x=now;h.y=g.y+1;h.z=g.x;
q.push(h);
}
}
t=g.x-z*10;
for(i=0;i<=9;i++)
{
now=t+i*10;
if(now!=g.x&&!vis[now]&&mark[now])
{
vis[now]=true;
h.x=now;h.y=g.y+1;h.z=g.x;
q.push(h);
}
}
t=g.x-w;
for(i=0;i<=9;i++)
{
now=t+i;
if(now!=g.x&&!vis[now]&&mark[now])
{
vis[now]=true;
h.x=now;h.y=g.y+1;h.z=g.x;
q.push(h);
}
}
}
if(flag)
printf("%d\n",res);
else
printf("Impossible\n");
}
return 0;
}
POJ3087 Shuffle'm Up
http://poj.org/problem?id=3087
题意:
有两摞牌,现在要求通过特定的洗牌方式得到要求的序列,洗牌时只能将两摞牌交叉在一起,第一摞的第一张在最上面,然后上面一半为新的第一裸,下面一半为新的后一半,求洗出要求序列的次数。思路:
其实是简单模拟题,那为什么在搜索题列表里,,,其实我也不知道什么情况(逃···就是模拟洗牌就行了,只要记录每次的序列,出现相同序列则无解,map或者set或者hash或者手写字典树等等,方法很多啦,
code:
#define N 512
int n,m;
int flag,sum,ave,ans,res,len,ans1,ans2;
int main()
{
int i,j,k,kk,t,x,y,z;
#ifndef ONLINE_JUDGE
freopen("test.txt","r",stdin);
#endif
map<string,bool> mp;
string s,ss,s1,s2;
cin>>k;
kk=0;
while(k--)
{
mp.clear();
scanf("%d",&n);
cin>>s1>>s2>>ss;
s=ss;
mp[ss]=true;
sum=0;
while(1)
{
sum++;
for(j=0,i=0;i<n;i++)
s[j++]=s2[i],s[j++]=s1[i];
if(s==ss)
{
printf("%d %d\n",++kk,sum);
break;
}
if(mp[s])
{
printf("%d -1\n",++kk);
break;
}
mp[s]=true;
s1.assign(s,0,n);s2.assign(s,n,n);
}
}
return 0;
}
FZU2150 Fire Game
http://poj.org/problem?id=3984http://acm.fzu.edu.cn/problem.php?pid=2150
题意:
两个熊孩子防火烧草堆,#代表草堆,点燃的草堆会在下一秒点燃周围上下左右的其他草堆,求所有草堆被烧完的最少时间,两个熊孩子不能烧完所有草堆输出-1.思路:
所有草堆分块,超过2个块则不能烧完,一开始想错,用了两次BFS第一次找到每个块最远的那个点,然后bfs从那个点扫回来找到最长路径,从而求出烧这些草堆的最小时间,但是当只有一块草堆时,两个起点并不确定,一开始以为直接把最长路分4段从中间两点开始就行,但是最长路外的次长路并不一定多长,所以这种解法错误。那么就只能暴力枚举所有的两个点的组合,bfs求出这两个点开始烧的时间,每一次都bfs依然会超时,可以提前以每一个点为起点bfs一次,确定当前起点时其他点被烧到的时间,然后枚举两点,直接得出所有其他点被烧到时间为这两点烧过去的最小值。
这题要敢于暴力枚举所有的两点组合,并且扫所有点,也就是有6层循环,同注意记录。
code:
#define N 15
int n,m;
int flag,sum,ave,ans,len,ans1,ans2;
int g[N][N];
int res[N][N][N][N];
int dir[4][2]={0,1,0,-1,1,0,-1,0};
bool vis[N][N];
char s[101];
struct node
{
int x,y;
int now;
}tn;
void bfs(int x,int y,int xx,int yy)
{
queue<node>q;
while(!q.empty())q.pop();
node a,b;
memset(vis,false,sizeof(vis));
a.x=xx;a.y=yy;a.now=0;
res[x][y][xx][yy]=0;
q.push(a);
vis[xx][yy]=true;
while(!q.empty())
{
a=q.front();q.pop();
for(int i=0;i<4;i++)
{
b=a;
b.x+=dir[i][0];b.y+=dir[i][1];
if(g[b.x][b.y]&&!vis[b.x][b.y])
{
vis[b.x][b.y]=true;
b.now=a.now+1;
res[x][y][b.x][b.y]=b.now;
q.push(b);
}
}
}
}
int main()
{
int i,j,k,kk,t,x,xx,y,yy,z;
scanf("%d",&k);
kk=0;
while(k--)
{
scanf("%d%d",&n,&m);
memset(g,0,sizeof(g));
for(i=1;i<=n;i++)
{
scanf("%s",s);
for(j=1;j<=m;j++)
if(s[j-1]=='#')
g[i][j]=1,ave++;
}
memset(res,0x3f,sizeof(res));
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
if(g[i][j])
bfs(i,j,i,j);
sum=INF;
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
if(g[i][j])
for(int ii=1;ii<=n;ii++)
for(int jj=1;jj<=m;jj++)
if(g[i][j]&&g[ii][jj])
{
ans=0;
for(int iii=1;iii<=n;iii++)
for(int jjj=1;jjj<=m;jjj++)
if(g[iii][jjj])
ans=max(ans,min(res[i][j][iii][jjj],res[ii][jj][iii][jjj]));
sum=min(sum,ans);
}
printf("Case %d: ",++kk);
if(sum==INF)
printf("-1\n");
else
printf("%d\n",sum);
}
return 0;
}
POJ3414 Pots
http://poj.org/problem?id=3414
题意:
有两个已知容量的杯子,要通过他们倒出c升水。思路:
常见的智力题,编程实现,每次只有6种情况,倒满1、倒满2、倒掉1,倒掉2,1倒给2,2倒给1,所以直接暴力bfs找结果就行了,代码有点挫,状态少习惯直接全写出来了,没错我就是懒的写个循环,,,code:
#define N 112345
int n,m;
int flag,sum,ave,ans,res,len,ans1,ans2,cnt;
bool vis[N];
char s[1000];
struct node
{
int now,x,y;
vector<int> s;
}tn;
node bfs()
{
queue<node>q;
while(!q.empty())q.pop();
node a,b; int t;
a.x=0;a.y=0;
a.now=0;a.s.clear();
vis[0]=true;
q.push(a);
while(!q.empty())
{
a=q.front();q.pop();
if(a.x==res||a.y==res)
return a;
b=a;
b.x=n;b.now++;b.s.push_back(1);
if(!vis[b.x*1000+b.y]){vis[b.x*1000+b.y]=true;q.push(b);}
b=a;
b.y=m;b.now++;b.s.push_back(2);
if(!vis[b.x*1000+b.y]){vis[b.x*1000+b.y]=true;q.push(b);}
b=a;
b.x=0;b.now++;b.s.push_back(3);
if(!vis[b.x*1000+b.y]){vis[b.x*1000+b.y]=true;q.push(b);}
b=a;
b.y=0;b.now++;b.s.push_back(4);
if(!vis[b.x*1000+b.y]){vis[b.x*1000+b.y]=true;q.push(b);}
b=a;
t=min(b.x+b.y,m);b.x=max(b.x+b.y-m,0);b.y=t;
b.now++;b.s.push_back(5);
if(!vis[b.x*1000+b.y]){vis[b.x*1000+b.y]=true;q.push(b);}
b=a;
t=min(b.x+b.y,n);b.y=max(b.x+b.y-n,0);b.x=t;
b.now++;b.s.push_back(6);
if(!vis[b.x*1000+b.y]){vis[b.x*1000+b.y]=true;q.push(b);}
}
a.now=-1;
return a;
}
int main()
{
int i,j,k,kk,t,x,y,z;
while(scanf("%d%d%d",&n,&m,&res)!=EOF&&n)
{
memset(vis,false,sizeof(vis));
tn=bfs();
if(tn.now==-1)
printf("impossible\n");
else
{
printf("%d\n",tn.now);
for(i=0;i<tn.now;i++)
{
if(tn.s[i]==1)
printf("FILL(1)\n");
if(tn.s[i]==2)
printf("FILL(2)\n");
if(tn.s[i]==3)
printf("DROP(1)\n");
if(tn.s[i]==4)
printf("DROP(2)\n");
if(tn.s[i]==5)
printf("POUR(1,2)\n");
if(tn.s[i]==6)
printf("POUR(2,1)\n");
}
}
}
return 0;
}
POJ3984 迷宫问题
http://poj.org/problem?id=3984题意:
给出一个5*5的0/1阵,0为可走,求从左上角到右下角的最短路径,思路:
BFS入门,可以回溯记录路径,但是为了方便直接写结构体里了。code:
#define N 15
int n,m;
int flag,sum,ave,ans,len,ans1,ans2;
#define N 11
int n,m;
int flag,sum,ave,ans,res,len,ans1,ans2;
int g[N][N];
int dir[4][2]={0,1,0,-1,1,0,-1,0};
bool vis[N][N];
struct node
{
int x,y,now;
vector<int> s;
}tn;
node bfs(int x,int y)
{
queue<node> q;
while(!q.empty())q.pop();
node a,b;
a.x=x;a.y=y;a.now=1;a.s.clear();a.s.push_back(0);
q.push(a);
vis[x][y]=true;
while(!q.empty())
{
a=q.front();q.pop();
if(a.x==5&&a.y==5)
return a;
for(int i=0;i<4;i++)
{
b=a;
b.x+=dir[i][0];b.y+=dir[i][1];
if(!vis[b.x][b.y]&&g[b.x][b.y])
{
vis[b.x][b.y]=true;
b.now=a.now+1;b.s.push_back((b.x-1)*10+(b.y-1));
q.push(b);
}
}
}
}
int main()
{
int i,j,k,kk,t,x,y,z;
memset(g,0,sizeof(0));
for(i=1;i<=5;i++)
for(j=1;j<=5;j++)
{
scanf("%d",&t);
g[i][j]=t?0:1;
}
memset(vis,false,sizeof(vis));
tn=bfs(1,1);
for(i=0;i<tn.now;i++)
printf("(%d, %d)\n",tn.s[i]/10,tn.s[i]%10);
return 0;
}
UVA11624 Fire!
https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2671
题意:
着火了,J要跑出这个房间,#是墙,F是火,火每秒点着周围的格子,求J跑出房间的最短时间。思路:
bfs两次,先将所有火的位置入队列,求出所有位置被火烧到的最短时间,然后bfsJ的所有逃跑路线找到在火烧到前的一条路线即可。code:
#define N 1123
int n,m;
int flag,sum,ave,ans,res,len,ans1,ans2;
int xx[N],yy[N];
int f[N][N];
int g[N][N];
int dir[4][2]={0,1,0,-1,1,0,-1,0};
bool vis[N][N];
char s[101];
struct node
{
int x,y;
int now;
}tn;
bool in(int x,int y)
{
return x<=n&&x>0&&y<=m&&y>0;
}
void bfsf()
{
queue<node>q;
while(!q.empty())q.pop();
node a,b;
memset(vis,false,sizeof(vis));
for(int i=0;i<sum;i++)
{
a.x=xx[i];a.y=yy[i];a.now=0;
q.push(a);
vis[a.x][b.y]=true;
}
while(!q.empty())
{
a=q.front();q.pop();
for(int i=0;i<4;i++)
{
b=a;
b.x=a.x+dir[i][0];b.y=a.y+dir[i][1];b.now=a.now+1;
if(!g[b.x][b.y]&&in(b.x,b.y)&&!vis[b.x][b.y])
{
f[b.x][b.y]=b.now;
vis[b.x][b.y]=true;
q.push(b);
}
}
}
}
int bfsj(int x,int y)
{
queue<node>q;
while(!q.empty())q.pop();
node a,b;
memset(vis,false,sizeof(vis));
a.x=x;a.y=y;a.now=0;
q.push(a);
vis[x][y]=true;
while(!q.empty())
{
a=q.front();q.pop();
for(int i=0;i<4;i++)
{
b=a;
b.x=a.x+dir[i][0];b.y=a.y+dir[i][1];b.now=a.now+1;
if(!g[b.x][b.y]&&!vis[b.x][b.y]&&b.now<f[b.x][b.y])
{
if(!in(b.x,b.y))
return b.now;
vis[b.x][b.y]=true;
q.push(b);
}
}
}
return -1;
}
int main()
{
int i,j,k,kk,t,x,y,z;
scanf("%d",&k);
while(k--)
{
scanf("%d%d",&n,&m);
memset(g,0,sizeof(g));
memset(f,0x3f,sizeof(f));
sum=0;
for(i=1;i<=n;i++)
{
scanf("%s",s);
for(j=1;j<=m;j++)
{
if(s[j-1]=='.')
continue;
g[i][j]=1;
if(s[j-1]=='J')
x=i,y=j;
if(s[j-1]=='F')
xx[sum]=i,yy[sum++]=j;
}
}
bfsf();
t=bfsj(x,y);
if(t==-1)
printf("IMPOSSIBLE\n");
else
printf("%d\n",t);
}
return 0;
}
HDU1241 Oil Deposits
http://acm.hdu.edu.cn/showproblem.php?pid=1241
题意:
有很多@油井,周围一圈内可以连接在一起的油井在同一个油田中,求有多少油田。思路:
bfs8个方向暴力即可。code:
<pre name="code" class="cpp">#define N 112
int n,m;
int flag,sum,ave,ans,res,len,ans1,ans2;
int g[N][N];
int dir[8][2]={1,0,1,1,1,-1,0,1,0,-1,-1,0,-1,-1,-1,1};
char s[101];
struct node
{
int x,y;
}tn;
void bfs(int x,int y)
{
queue<node>q;
while(!q.empty())q.pop();
node a,b;
a.x=x;a.y=y;
q.push(a);
while(!q.empty())
{
a=q.front();q.pop();
for(int i=0;i<8;i++)
{
b.x=a.x+dir[i][0];b.y=a.y+dir[i][1];
if(g[b.x][b.y])
q.push(b);
g[b.x][b.y]=0;
}
}
}
int main()
{
int i,j,k,kk,t,x,y,z;
while(scanf("%d%d",&n,&m)!=EOF&&n)
{
memset(g,0,sizeof(g));
for(i=1;i<=n;i++)
{
scanf("%s",s);
for(j=1;j<=m;j++)
if(s[j-1]=='@')
g[i][j]=1;
}
sum=0;
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
if(g[i][j])
{
sum++;
bfs(i,j);
}
printf("%d\n",sum);
}
return 0;
}
HDU1495 非常可乐
http://acm.hdu.edu.cn/showproblem.php?pid=1495题意:
给出两个已知容量的杯子和一瓶可乐,杯子容量和等于可乐,求是否能平均分为两半,所需最少步骤。思路:
奇数必然无解,偶数bfs,与前面分水那题基本相同。code:
#define N 112345
int n,m,v,u;
int flag,sum,ave,ans,res,len,ans1,ans2;
bool vis[N];
char s[101];
struct node
{
int x,y,z;
int now;
}tn;
int bfs()
{
queue<node>q;
while(!q.empty())q.pop();
node a,b;
memset(vis,false,sizeof(vis));
a.x=0;a.y=0;a.z=n;a.now=0;
q.push(a);vis[0]=true;
while(!q.empty())
{
a=q.front();q.pop();
if(a.x==n/2||a.y==n/2||a.z==n/2)
return a.x&&a.y&&a.z?a.now+1:a.now;
b=a;
b.x=u;b.z=a.z-(u-a.x);b.now++;
if(!vis[b.x*1000+b.y])
q.push(b);
vis[b.x*1000+b.y]=true;
b=a;
b.y=v;b.z=a.z-(v-a.y);b.now++;
if(!vis[b.x*1000+b.y])
q.push(b);
vis[b.x*1000+b.y]=true;
b=a;
b.x=0;b.z=a.z+a.x;b.now++;
if(!vis[b.x*1000+b.y])
q.push(b);
vis[b.x*1000+b.y]=true;
b=a;
b.y=0;b.z=a.z+a.y;b.now++;
if(!vis[b.x*1000+b.y])
q.push(b);
vis[b.x*1000+b.y]=true;
b=a;
b.x=min(u,a.x+a.y);b.y=max(a.x+a.y-u,0);b.now++;
if(!vis[b.x*1000+b.y])
q.push(b);
vis[b.x*1000+b.y]=true;
b=a;
b.y=min(v,b.x+b.y);b.x=max(a.x+a.y-v,0);b.now++;
if(!vis[b.x*1000+b.y])
q.push(b);
vis[b.x*1000+b.y]=true;
}
return -1;
}
int main()
{
int i,j,k,kk,t,x,y,z;
while(scanf("%d%d%d",&n,&u,&v)!=EOF&&n)
{
t=n&1?-1:bfs();
if(t==-1)
printf("NO\n");
else
printf("%d\n",t);
}
return 0;
}
HDU2612 Find a way
http://acm.hdu.edu.cn/showproblem.php?pid=2612
题意:
Y和M要一起去一个kfc,每走一格需要11分钟,求他们去哪个kfc所需总时间和最少,思路:
bfs两次,将两个人到每个kfc的时间打表,然后找出和最小的那个。code:
#define N 212
int n,m;
int flag,sum,ave,ans,res,len,ans1,ans2;
int f[N][N],ff[N][N];
int g[N][N];
int dir[4][2]={0,1,0,-1,1,0,-1,0};
bool vis[N][N];
char s[N];
struct node
{
int x,y;
int now;
}tn;
void bfsy(int x,int y)
{
queue<node>q;
while(!q.empty())q.pop();
node a,b;
a.x=x;a.y=y;a.now=0;
q.push(a);
f[x][y]=0;
while(!q.empty())
{
a=q.front();q.pop();
for(int i=0;i<4;i++)
{
b=a;
b.x+=dir[i][0];b.y+=dir[i][1];b.now++;
if(g[b.x][b.y]&&f[b.x][b.y]==INF)
{
q.push(b);
f[b.x][b.y]=b.now;
}
}
}
}
void bfsm(int x,int y)
{
queue<node>q;
while(!q.empty())q.pop();
node a,b;
a.x=x;a.y=y;a.now=0;
q.push(a);
ff[x][y]=0;
while(!q.empty())
{
a=q.front();q.pop();
for(int i=0;i<4;i++)
{
b=a;
b.x+=dir[i][0];b.y+=dir[i][1];b.now++;
if(g[b.x][b.y]&&ff[b.x][b.y]==INF)
{
q.push(b);
ff[b.x][b.y]=b.now;
}
}
}
}
int main()
{
int i,j,k,kk,t,x,y,xx,yy,z;
while(scanf("%d%d",&n,&m)!=EOF&&n)
{
memset(g,0,sizeof(g));
for(i=1;i<=n;i++)
{
scanf("%s",s);
for(j=1;j<=m;j++)
{
if(s[j-1]=='#')
continue;
g[i][j]++;
if(s[j-1]=='@')
g[i][j]++;
if(s[j-1]=='Y')
x=i,y=j;
if(s[j-1]=='M')
xx=i,yy=j;
}
}
memset(f,0x3f,sizeof(f));
memset(ff,0x3f,sizeof(ff));
bfsy(x,y);
bfsm(xx,yy);
res=INF;
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
if(g[i][j]==2)
res=min(res,f[i][j]+ff[i][j]);
printf("%d\n",11*res);
}
return 0;
}
HDU-1430 魔板
http://blog.csdn.net/kopyh/article/details/48517595
HDU-3567 Eight II
http://blog.csdn.net/kopyh/article/details/48738709
HDU-2181 哈密顿绕行世界问题
http://blog.csdn.net/kopyh/article/details/48738747
HDU-3533 Escape
http://blog.csdn.net/kopyh/article/details/48738787
HDU-1560 DNA sequence
http://blog.csdn.net/kopyh/article/details/48738975
ZOJ-2477 Magic Cube
http://blog.csdn.net/kopyh/article/details/48739097
HDU-3085 Nightmare Ⅱ
http://blog.csdn.net/kopyh/article/details/48739333
HDU-1067 GAP
http://blog.csdn.net/kopyh/article/details/48739601
HDU-2102 A计划
http://blog.csdn.net/kopyh/article/details/48742173
HDU-3001 Travelling
http://blog.csdn.net/kopyh/article/details/48742311
HDU 5113 Black And White
http://blog.csdn.net/kopyh/article/details/48999173
HDU 4499 Cannon
http://blog.csdn.net/kopyh/article/details/49072247