DFS
来源:互联网 发布:怎么重置mac 编辑:程序博客网 时间:2024/04/30 18:18
ZOJ3607 油田问题的变形,主要靠怎么找到相邻点对应的相邻边 然后进行比较
1.要注意dx dy 与 edge中四个方向匹配,数组下标与坐标系的方向是不一样的
2.f==0&&edge[x][0]==1&&edge[y][2]==1 f是用来表示判断哪条相邻边的,不能写成edge[x][0]==edge[y][2],会出现都等于0的情况
#include<iostream>#include<cstdio>#include<cstring>#include<string>#define MAXN 55using namespace std;int vis[MAXN][MAXN],dota[MAXN][MAXN];int n,m;int dx[4]={0,-1,0,1};int dy[4]={-1,0,1,0};int edge[12][5]={{1,1,0,0},{0,1,1,0},{1,0,0,1},{0,0,1,1},{0,1,0,1},{1,0,1,0},{1,1,1,0},{1,1,0,1},{1,0,1,1},{0,1,1,1},{1,1,1,1}};int fun(int x,int y,int f){ if(f==0&&edge[x][0]==1&&edge[y][2]==1)return 1; if(f==2&&edge[x][2]==1&&edge[y][0]==1)return 1; if(f==1&&edge[x][1]==1&&edge[y][3]==1)return 1; if(f==3&&edge[x][3]==1&&edge[y][1]==1)return 1; return 0;}void dfs(int a,int b){ vis[a][b]=1; int p1,p2; p1=dota[a][b]; for(int i=0;i<4;i++) { int x=a+dx[i]; int y=b+dy[i]; if(x>=0&&x<n&&y>=0&&y<m&&!vis[x][y]) { p2=dota[x][y]; //printf("//%d %d %d %d %d\n",x,y,p1,p2,i); if(fun(p1,p2,i))//可连递归 { // printf("//%d %d %d %d %d\n",x,y,p1,p2,i); dfs(x,y); } } }}int main(){ // a[0]={} while(cin>>n>>m) { if(n<=0||m<=0)break; int i,j; char ch; for(i=0;i<n;i++) { for(j=0;j<m;j++) { cin>>ch; dota[i][j]=ch-'A'; } } memset(vis,0,sizeof(vis)); int sum=0; for(i=0;i<n;i++) { for(j=0;j<m;j++){ if(!vis[i][j]){ sum++; // printf("*** %d %d\n",i,j); dfs(i,j); } } } printf("%d\n",sum); } return 0;}
ZOJ2734
题意是给不同价值卡片若干张,问几种方法可以凑成数字n
#include<cstdio>#include<cstring>using namespace std;int n,m,way,sum;int num[1010];void dfs(int x){ if(sum==n){ way++; return; } for(int i=x;i<=n;i++)//超过n-sum后无意义,从x开始(精髓) { if(num[i]) { if(sum+i>n)return; sum+=i; num[i]--; dfs(i); num[i]++; sum-=i; } }}int main(){ int k=0; while(~scanf("%d%d",&n,&m)) { int x,y,i; memset(num,0,sizeof(num)); for(i=0;i<m;i++){ scanf("%d%d",&x,&y); num[x]=y; } sum=0; way=0; dfs(0); if(k)printf("\n"); k=1; printf("%d\n",way); } return 0;}
ZOJ1666
方法与上题同,不赘述
#include<cstdio>#include<cstring>using namespace std;int n,num[18],sum,way;void dfs(int x){ if(sum==n) { way++; return; } for(int i=x;i<17;i++) { if(sum+num[i]>n)return; sum+=num[i]; dfs(i); sum-=num[i]; }}int main(){ for(int i=1;i<=17;i++)num[i-1]=i*i; while(~scanf("%d",&n)&&n) { sum=0; way=0; dfs(0); printf("%d\n",way); } return 0;}
ZOJ1457素数环
简单的dfs,但要考虑一点:n位奇数时不会有答案,因为奇数个数必有两个加起来是偶数
#include <cstdio>#include <cstring>#include <iostream>using namespace std;#define N 100int pri[N],n,vis[N],ans[N];void dfs(int s,int cnt){ int i; ans[cnt]=s; // if(cnt>n)return; if(cnt==n) { if(!pri[s+1]){ for(i=1;i<=n;i++) { if(i==1)printf("%d",ans[i]); else printf(" %d",ans[i]); } printf("\n"); } return; } for(i=2;i<=n;i++) { if(!vis[i]&&!pri[s+i]) { vis[i]=1; dfs(i,cnt+1); vis[i]=0; } }}int main(){ memset(pri,0,sizeof(pri)); pri[0]=1; pri[1]=1; int i,j,k=1; for(i=2;i<N;i++) { for(j=i*i;j<N;j+=i)pri[j]=1; } // for(i=0;i<100;i++)if(!pri[i])printf("%d\n",i); while(cin>>n) { memset(vis,0,sizeof(vis)); vis[1]=1; printf("Case %d:\n",k++); if(n%2==0) dfs(1,1); printf("\n"); } return 0;}
ZOJ1711
简单的dfs,关键是去重,本来以为重复的一定是上一个输出等于下一个输出,没想到中间还会隔几个
比如 9 9 5 5 4 4 3 3 2 2 1 1这个例子
应该输出:
Sums of 9:
5+4
5+3+1
5+2+2
4+4+1
4+3+2
4+2+2+1
3+3+2+1
代码:
#include<iostream>#include<cstdio>#include<string>#include<cstring>using namespace std;int a[20],vis[20],n,m;int ans[20],f;int pre[1000][20],num;int quchong(int cnt){ int i,j,s; for(int i=0;i<num;i++) { s=0; for(j=0;j<cnt;j++){ if(pre[i][j]==ans[j])s++; } if(s==cnt)return 1; } return 0;}void dfs(int sum,int cnt,int k){ int i; if(sum>n)return; // printf(" %d %d\n",sum,cnt); if(sum==n){ f=1; if(quchong(cnt))return; for(i=0;i<cnt;i++){ if(i==0)printf("%d",ans[i]); else printf("+%d",ans[i]); } printf("\n"); for(i=0;i<cnt;i++)pre[num][i]=ans[i]; num++; // for(i=0;i<str.size();i++)printf("%d\n",str[i]); } for(i=k;i<m;i++) { if(!vis[i]) { vis[i]=1; ans[cnt]=a[i]; dfs(sum+a[i],cnt+1,i+1); vis[i]=0; } }}int main(){ while(cin>>n>>m) { if(n==0)break; int i; for(i=0;i<m;i++)cin>>a[i]; memset(vis,0,sizeof(vis)); f=0; num=0; memset(pre,-1,sizeof(pre)); printf("Sums of %d:\n",n); dfs(0,0,0); if(f==0)printf("NONE\n"); } return 0;}/*9 9 5 5 4 4 3 3 2 2 1 1*/
ZOJ3706
题意:
两个正整数的砝码,把其中一个分成正整数的部分,用这三个砝码能称量哪些重量(正整数)。
解法:
枚举分哪个、分成多少,dfs搜。
画个树状图就很好理解,暴力强搜就可以了。
#include<cstdio>#include<iostream>#include<cstring>using namespace std;int num[3];int cnt;int vis[300];void dfs(int n,int val){ if(n>3)return; if(val>0&&!vis[val]) { vis[val]=1; cnt++; } dfs(n+1,val+num[n]); dfs(n+1,val-num[n]); dfs(n+1,val);}int main(){ int t; cin>>t; while(t--) { int n,m,ma,i; cin>>n>>m; ma=0; num[3]=0; for(i=1;i<=n/2;i++) { memset(vis,0,sizeof(vis)); num[0]=i; num[1]=n-i; num[2]=m; cnt=0; dfs(0,0); if(cnt>ma)ma=cnt; } for(i=1;i<=m/2;i++) { memset(vis,0,sizeof(vis)); num[0]=i; num[1]=m-i; num[2]=n; cnt=0; dfs(0,0); if(cnt>ma)ma=cnt; } printf("%d\n",ma); } return 0;}
0 0