温故而知新
vj地址:here
POJ1321
简单dfs
对于给定形状和大小的棋盘,摆放k个棋子的所有可行的摆放方案数C
第i行放或者不放棋子,并记录第j列是否放过棋子,如果最后棋子数正好为k则为可行方案
#include<iostream> #include<cstdio> #include<cstring> using namespace std; int n,k; char map[10][10]; bool vis[10]; int cnt; void dfs(int i,int num) { if(num==k) { cnt++; return; } if(i>=n)return; //i int j; for(j=0;j<n;j++) { if(!vis[j]&&map[i][j]=='#') { vis[j]=true; dfs(i+1,num+1); vis[j]=false; } } //i+1 dfs(i+1,num); } int main() { while(~scanf("%d%d",&n,&k)) { if(n==-1&&k==-1)break; int i; for(i=0;i<n;i++)scanf("%s",map[i]); cnt=0; memset(vis,false,sizeof(vis)); dfs(0,0); printf("%d\n",cnt); } return 0; }
POJ3297
奶牛翻棋盘,每次会翻上下左右中五个位置
用二进制枚举第一行的状态,后面每行的状态就确定了,也就是根据上一行的状态确定要不要pushon,
然后检查最后一行是不是全为0,如果是就找到的方案
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int n,m; int mp[20][20],p[20][20],ans[20][20]; void pushon(int x,int y) { p[x][y]^=1; p[x-1][y]^=1; p[x+1][y]^=1; p[x][y-1]^=1; p[x][y+1]^=1; } bool check(int x) { memset(ans,0,sizeof(ans)); memcpy(p,mp,sizeof(mp)); for(int i=1;i<=m;i++) { if(x&(1<<(i-1))) { ans[1][i]=1; pushon(1,i); } } for(int i=2;i<=n;i++) { for(int j=1;j<=m;j++) { if(p[i-1][j]) { ans[i][j]=1; pushon(i,j); } } } for(int i=1;i<=m;i++) { if(p[n][i])return false; } return true; } int main() { while(~scanf("%d%d",&n,&m)) { for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) scanf("%d",&mp[i][j]); } int tt=(1<<m); int flag=1; for(int i=0;i<tt;i++)//用二进制枚举第一行所有翻转的可能 { if(check(i)) { flag=0; break; } } if(flag) { puts("IMPOSSIBLE"); continue; } for(int i=1;i<=n;i++) { for(int j=1;j<m;j++)printf("%d ",ans[i][j]); printf("%d\n",ans[i][m]); } } return 0; }
POJ 1426
找到一个数的任意一个倍数,要求只包含0和1
倍数可能比较大,利用同余模定理,用string来记录数字
dfs解法
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define LL long long int flag; string ans[210]; void dfs(string str,int s,int n,int level) { if(flag||level>=100){ return; } if(s==0){ flag=1; ans[n]=str; return ; } dfs(str+'1',(s*10+1)%n,n,level+1); dfs(str+'0',(s*10+0)%n,n,level+1); } int main() { for(int i=1;i<=200;i++) { flag=0; dfs("1",1,i,1); } int n; while(~scanf("%d",&n)&&n!=0) { printf("%s\n",ans[n].c_str()); } return 0; }
bfs+剪枝 访问过的余数就不要访问了
#include<iostream> #include<cstdio> #include<cstring> #include<queue> #include<algorithm> using namespace std; #define LL long long struct ss { int s; string str; }t; queue<ss>q; string s[220]; bool vis[220]; void bfs(int n) { memset(vis,false,sizeof(vis)); ss a; a.s=1; a.str="1"; while(!q.empty())q.pop(); q.push(a); while(!q.empty()) { a=t=q.front(); q.pop(); if(t.s%n==0) { s[n]=t.str; return ; } a.s=(a.s*10+1)%n; if(!vis[a.s]){ a.str+='1'; q.push(a); vis[a.s]=true; } t.s=(t.s*10+0)%n; if(!vis[t.s]){ t.str+='0'; q.push(t); vis[t.s]=true; } } } int main() { for(int i=1;i<=200;i++){ bfs(i); } int n; while(~scanf("%d",&n)&&n!=0) { printf("%s\n",s[n].c_str()); } return 0; }
POJ3126
一个四位数素数,要求改变一个数字,并且改变后仍为素数,问得到目标数字要变几次
传统广搜+剪枝,同样是剪掉访问过的前置节点
#include<iostream> #include<cstdio> #include<cstring> #include<queue> #include<algorithm> using namespace std; #define LL long long #define maxn 10000 struct ss { int num; int step; }; bool vis[maxn]; queue<ss>q; bool pri[maxn]; void bfs(int a,int b) { memset(vis,false,sizeof(vis)); while(!q.empty())q.pop(); ss t,o; t.num=a; t.step=0; vis[t.num]=true; q.push(t); while(!q.empty()) { t=q.front(); q.pop(); // printf("%d %d\n",t.num,t.step); if(t.num==b) { printf("%d\n",t.step); return; } for(int i=1;i<=9;i++) { int p=i*1000+t.num%1000; if(!vis[p]&&!pri[p]) { vis[p]=true; o.num=p; o.step=t.step+1; q.push(o); } } for(int i=0;i<=9;i++) { int p=t.num/1000*1000+i*100+t.num%100; if(!vis[p]&&!pri[p]) { vis[p]=true; o.num=p; o.step=t.step+1; q.push(o); } } for(int i=0;i<=9;i++) { int p=t.num/100*100+i*10+t.num%10; if(!vis[p]&&!pri[p]) { vis[p]=true; o.num=p; o.step=t.step+1; q.push(o); } } for(int i=0;i<=9;i++) { int p=t.num/10*10+i; if(!vis[p]&&!pri[p]) { vis[p]=true; o.num=p; o.step=t.step+1; q.push(o); } } } } void inti() { memset(pri,false,sizeof(pri)); pri[0]=pri[1]=1; for(int i=2;i<maxn;i++) { for(int j=i+i;j<maxn;j+=i) { pri[j]=1; } } } int main() { inti(); int T; scanf("%d",&T); while(T--) { int a,b; scanf("%d%d",&a,&b); if(a==b) { puts("0"); continue; } bfs(a,b); } return 0; }
POJ3087
两副牌,交叉洗牌后得到新的系列,问几次能得到目标序列
简单dfs,由目标序列向前递归求解。指针引用和原指针指向的是同一个字符串,指针引用值改变会改变原指针对应的值,传入前先复制字符串
#include<iostream> #include<cstdio> #include<cstring> #include<queue> #include<algorithm> using namespace std; #define LL long long #define maxn 1100 char a1[maxn],a2[maxn]; char a3[maxn*2]; int n; int flag; bool isEqual(char *a,char *b,int len) { for(int i=0;i<len;i++) { if(a[i]!=b[i]) return false; } return true; } void dfs(char *s3,int level) { if(flag)return ; char s1[maxn],s2[maxn]; for(int i=0;i<n;i++) { if(i%2)s1[i/2]=s3[i]; else s2[i/2]=s3[i]; } s1[n/2]=s2[n/2]='\0'; if(isEqual(s1,a1,n/2)&&isEqual(s2,a2,n/2)) { flag=level; return ; } for(int i=0;i<n/2;i++) { s3[i]=s1[i]; } for(int i=n/2;i<n;i++) { s3[i]=s2[i-n/2]; } // printf("%s %s %s\n",s1,s2,s3); if(isEqual(s3,a3,n)) { flag=-1; return ; } dfs(s3,level+1); } int main() { int T; scanf("%d",&T); for(int i=1;i<=T;i++) { scanf("%d%s%s%s",&n,a1,a2,a3); n*=2; flag=0; char a33[maxn]; strcpy(a33,a3); dfs(a33,1); printf("%d %d\n",i,flag); } return 0; }
FZU2150
做过,传送门:here
UVA 11624
帮助joe逃离火灾,走到边界就算逃离。joe只要一个,火没说有几处。
bfs每一步要先把人走完,再把火势走完,分别标记,如果人走之前有火的标记,则说明人来不及走,那么这条路就不能走
另外注意剪枝要细,原先我在火势走的时候是判断mp[t.x][t.y]!='#' 结果超时了,改成mp[t.x][t.y]=='.' || mp[t.x][t.y]=='J'就好了
#include<iostream> #include<cstdio> #include<cstring> #include<queue> #include<algorithm> using namespace std; #define LL long long char mp[1010][1010]; int r,c; // l u r d int dx[4]={-1,0,1,0}; int dy[4]={0,-1,0,1}; struct Point { int x,y,step; Point(int _x,int _y,int _step):x(_x),y(_y),step(_step){} }; int flag; void bfs() { queue<Point>joe,fire; while(!joe.empty())joe.pop(); while(!fire.empty())fire.pop(); for(int i=0;i<r;i++) { for(int j=0;j<c;j++) { if(mp[i][j]=='J') joe.push(Point(i,j,0)); if(mp[i][j]=='F') fire.push(Point(i,j,0)); } } int step=0; while(!joe.empty()) { //人先走 将该步step的下一步全部更新完 while(!joe.empty() && joe.front().step==step){ Point t=joe.front(); joe.pop(); // printf("joe: %d %d %d %c\n",t.x,t.y,t.step,mp[t.x][t.y]); if(mp[t.x][t.y]!='F')//没被火烧到才能走 { if(t.x==r-1 || t.x==0 || t.y==c-1 || t.y==0)//走到边界 { flag=t.step+1; return; } for(int i=0;i<4;i++) { int x=t.x+dx[i]; int y=t.y+dy[i]; if(x>=0 && x<r && y>=0 && y<c && mp[x][y]=='.') { mp[x][y]='J'; joe.push(Point(x,y,t.step+1)); } } } } //火蔓延 更新完该步 while(!fire.empty() && fire.front().step==step){ Point t=fire.front(); fire.pop(); // printf("fire: %d %d %d %c\n",t.x,t.y,t.step,mp[t.x][t.y]); for(int i=0;i<4;i++) { int x=t.x+dx[i]; int y=t.y+dy[i]; if(x>=0 && x<r && y>=0 && y<c && (mp[x][y]=='.'||mp[x][y]=='J')) { mp[x][y]='F'; fire.push(Point(x,y,t.step+1)); } } } step++; } } int main() { int T; scanf("%d",&T); while(T--) { scanf("%d%d",&r,&c); for(int i=0;i<r;i++){ scanf("%s",mp[i]); } flag=0; bfs(); if(flag)printf("%d\n",flag); else puts("IMPOSSIBLE"); } return 0; } /* 2 4 5 ##### #J..# #..F# #...# 4 4 #### #J.# #.F# #..# */
POJ3414
两个杯子倒水,6种情况,要求最后杯中水量都为C
简单bfs ,6种情况都考虑到即可
#include<iostream> #include<cstdio> #include<cstring> #include<queue> #include<algorithm> using namespace std; #define LL long long #define FA "\nFILL(1)" #define FB "\nFILL(2)" #define DA "\nDROP(1)" #define DB "\nDROP(2)" #define PAB "\nPOUR(1,2)" #define PBA "\nPOUR(2,1)" bool mp[110][110]; struct node { int step; int va,vb; string path; }; int flag; queue<node>q; void bfs(int VA,int VB,int C) { memset(mp,false,sizeof(mp)); node p; p.va=0; p.vb=0; p.step=0; p.path=""; while(!q.empty())q.pop(); q.push(p); while(!q.empty()) { p=q.front(); q.pop(); if(p.va==C || p.vb==C) { flag=p.step; printf("%d%s",flag,p.path.c_str()); return; } node t; //FILLA t.va=VA; t.vb=p.vb; if(!mp[t.va][t.vb]) { mp[t.va][t.vb]=true; t.step=p.step+1; t.path=p.path+FA; q.push(t); } //FILLB t.va=p.va; t.vb=VB; if(!mp[t.va][t.vb]) { mp[t.va][t.vb]=true; t.step=p.step+1; t.path=p.path+FB; q.push(t); } //DROPA t.va=0; t.vb=p.vb; if(!mp[t.va][t.vb]) { mp[t.va][t.vb]=true; t.step=p.step+1; t.path=p.path+DA; q.push(t); } //DROPB t.va=p.va; t.vb=0; if(!mp[t.va][t.vb]) { mp[t.va][t.vb]=true; t.step=p.step+1; t.path=p.path+DB; q.push(t); } //POURAB t.va=max(0,p.va-(VB-p.vb)); t.vb=p.va-t.va+p.vb; if(!mp[t.va][t.vb]) { mp[t.va][t.vb]=true; t.step=p.step+1; t.path=p.path+PAB; q.push(t); } //POURBA t.vb=max(0,p.vb-(VA-p.va)); t.va=p.vb-t.vb+p.va; if(!mp[t.va][t.vb]) { mp[t.va][t.vb]=true; t.step=p.step+1; t.path=p.path+PBA; q.push(t); } } } int main() { int a,b,c; while(~scanf("%d%d%d",&a,&b,&c)) { flag=0; bfs(a,b,c); if(!flag)puts("impossible"); } return 0; }
HDU1495
一瓶可乐,两个杯子,要求最后两杯中可乐一样且正好都是半瓶的量。
简单bfs,考虑6种情况即可,一定要等分地分成两杯
#include<iostream> #include<cstdio> #include<cstring> #include<queue> #include<algorithm> using namespace std; bool mp[110][110]; int N,M,S; struct node{ int vn,vm,vs,step; }; queue<node>q; void bfs() { memset(mp,false,sizeof(mp)); node a; a.vn=a.vm=a.step=0; a.vs=S; while(!q.empty())q.pop(); q.push(a); mp[a.vn][a.vm]=true; while(!q.empty()) { a=q.front(); q.pop(); // printf("s=%d n=%d m=%d step=%d\n",a.vs,a.vn,a.vm,a.step); if(a.vs==max(a.vm,a.vn) && a.vs==S/2) { printf("%d\n",a.step); return; } //n->m node t; t.vn=max(0,a.vn-(M-a.vm)); t.vm=a.vn-t.vn+a.vm; t.vs=a.vs; if(!mp[t.vn][t.vm]) { mp[t.vn][t.vm]=true; t.step=a.step+1; q.push(t); } //m->n t.vm=max(0,a.vm-(N-a.vn)); t.vn=a.vm-t.vm+a.vn; t.vs=a.vs; if(!mp[t.vn][t.vm]) { mp[t.vn][t.vm]=true; t.step=a.step+1; q.push(t); } //n->s t.vn=max(0,a.vn-(S-a.vs)); t.vs=a.vn-t.vn+a.vs; t.vm=a.vm; if(!mp[t.vn][t.vm]) { mp[t.vn][t.vm]=true; t.step=a.step+1; q.push(t); } //s->n t.vs=max(0,a.vs-(N-a.vn)); t.vn=a.vs-t.vs+a.vn; t.vm=a.vm; if(!mp[t.vn][t.vm]) { mp[t.vn][t.vm]=true; t.step=a.step+1; q.push(t); } //m->s t.vm=max(0,a.vm-(S-a.vs)); t.vs=a.vm-t.vm+a.vs; t.vn=a.vn; if(!mp[t.vn][t.vm]) { mp[t.vn][t.vm]=true; t.step=a.step+1; q.push(t); } //s->m t.vs=max(0,a.vs-(M-a.vm)); t.vm=a.vs-t.vs+a.vm; t.vn=a.vn; if(!mp[t.vn][t.vm]) { mp[t.vn][t.vm]=true; t.step=a.step+1; q.push(t); } } puts("NO"); } int main() { while(~scanf("%d%d%d",&S,&N,&M)) { if(S==0&&N==0&&M==0)break; if(S%2) { puts("NO"); continue; } bfs(); } return 0; }
HDU2612
两人去一家KFC,要求选择两人总路程最短的其中一家KFC。
简单题bfs 只要以两个人为起点各自进行bfs求出到各个餐厅的最短距离,然后暴力出最小值即可。
#include<iostream> #include<cstdio> #include<cstring> #include<queue> #include<algorithm> using namespace std; int n,m; char mp[220][220]; int yy[220][220]; int mm[220][220]; int dx[4]={-1,0,1,0}; int dy[4]={0,-1,0,1}; bool vis[220][220]; struct node { int x,y,step; node(int _x,int _y,int _step):x(_x),y(_y),step(_step){} }; queue<node>q; void bfs() { memset(vis,false,sizeof(vis)); while(!q.empty())q.pop(); for(int i=0;i<n;i++) { for(int j=0;j<m;j++) { if(mp[i][j]=='Y') { q.push(node(i,j,0)); } } } vis[q.front().x][q.front().y]=true; while(!q.empty()) { node t=q.front(); q.pop(); yy[t.x][t.y]=t.step; for(int i=0;i<4;i++) { int x=t.x+dx[i]; int y=t.y+dy[i]; if(x>=0 && x<n && y>=0 && y<m && mp[x][y]!='#' && !vis[x][y] ) { vis[x][y]=true; q.push(node(x,y,t.step+1)); } } } memset(vis,false,sizeof(vis)); while(!q.empty())q.pop(); for(int i=0;i<n;i++) { for(int j=0;j<m;j++) { if(mp[i][j]=='M') { q.push(node(i,j,0)); } } } vis[q.front().x][q.front().y]=true; while(!q.empty()) { node t=q.front(); q.pop(); mm[t.x][t.y]=t.step; for(int i=0;i<4;i++) { int x=t.x+dx[i]; int y=t.y+dy[i]; if(x>=0 && x<n && y>=0 && y<m && mp[x][y]!='#' && !vis[x][y] ) { vis[x][y]=true; q.push(node(x,y,t.step+1)); } } } int ma=100000000; for(int i=0;i<n;i++) { for(int j=0;j<m;j++) { if(mp[i][j]=='@') { if(yy[i][j]+mm[i][j]<ma) { ma=yy[i][j]+mm[i][j]; } } } } printf("%d\n",ma*11); } int main() { while(~scanf("%d%d",&n,&m)) { for(int i=0;i<n;i++) scanf("%s",mp[i]); bfs(); } return 0; }
浙公网安备 33010602011771号