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 55
using 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 100
int 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;
}