DFS

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





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章