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;
}