搜索专题

POJ  Best Sequence

http://poj.org/problem?id=1699

题意:给你n个字符窜,求其所能拼接的最短长度。

分析:预处理下,dp[i][j]表示j接在i后头的最短长度,然后记忆化搜索
         这里注意的是 ACTT
                             CT   这个答案是6 因为T和/0不相等

        还有就是刚进入的时候,要把当前的字符窜算进去,应为pos代表的是前一个,若带入是-1的话,会超出数组。
        dp[i][j]表示状态i,第j个结尾。

#include<stdio.h>

#include<algorithm>

#include<string.h>

using namespace std;

const int MN=30;

const int INF=999999;

char s[MN][MN];

int dp[MN][MN];//j接在i后头最短是多长

int f[1024][MN];

int n;



int judge(int len1,int len2,int pos1,int pos2)

{

    int ans=len2,tmp,tt=0;

    if(len1>len2) tt=len1-len2;

    for(int i=tt; i<len1; i++)

    {

        tmp=len2;

        if(s[pos1][i]==s[pos2][0])

        {

            int x=i,y=0;

            while(1)

            {

                if(s[pos1][x++]!=s[pos2][y++]) break;

                if(x==len1) return len2-y;

            }

        }

    }

    return len2;

}



void work()

{

    for(int i=0; i<n; i++)

    {

        int len1=strlen(s[i]);

        for(int j=0; j<n; j++)

        {

            if(i==j) continue;

            int len2=strlen(s[j]);

            int tmp=judge(len1,len2,i,j);

            dp[i][j]=tmp;

        }

    }

}



int DFS(int ans,int pos)

{

    if(f[ans][pos]!=-1) return f[ans][pos];

    if(ans==0) return f[ans][pos]=0;

    int sum=INF;

    for(int i=0; i<n; i++)

    {

        if(ans&(1<<i))

        {

            ans^=(1<<i);

            int tmp=DFS(ans,i)+dp[pos][i];

            ans^=(1<<i);

            if(sum>tmp)

            {

                sum=tmp;

               // de[i]=pos;

            }

        }

    }

    return f[ans][pos]=sum;

}



void debug1()

{

    for(int i=0; i<n; i++)

    {

        printf("%d: ",i);

        for(int j=0; j<n; j++)

            if(i!=j) printf("%d ",dp[i][j]);

        puts("");

    }

}



int main()

{

    int i,j,T;

    scanf("%d",&T);

    while(T--)

    {

        memset(f,-1,sizeof(f));

        scanf("%d",&n);

        memset(dp,0,sizeof(dp));

        for(i=0; i<n; i++)

        {

            scanf("%s",s[i]);

        }

        work();

       // debug1();

        int sum=INF;

        for(i=0; i<n; i++)

        {

            int l=strlen(s[i]);

            int tmp=(1<<n)-1;

            tmp^=(1<<i);

            f[(1<<n)-1][i]=l+DFS(tmp,i);

        }

        int tt;

        for(i=0; i<n; i++)

        {

            if(sum>f[(1<<n)-1][i])

            {

                sum=f[(1<<n)-1][i];

            }

        }

        printf("%d\n",sum);

    }

    return 0;

}
View Code

 

POJ 1950 Dessert
http://poj.org/problem?id=1950
题意:n个数1 2 3.......n,加入运算符使其结果为0
分析:dfs搜索,具体看代码,主要是几个数字结合的时候,前一个数要先减去,再加上结合的数。
        9.10=9*100+10  而不是9*10+10
        还有这里只打印前20个

#include<stdio.h>

#include<string.h>

#include<algorithm>

using namespace std;

#define LL long long

int cas;

const int MN=20;

char num[2000][100];

char tmp[MN*MN];

int n;



void DFS(int cur,LL sum,int cnt,LL pre,int flag)

{//当前第几个数,当前的和,当前字符个数,前一个数十什么,前一个符号是+还是-

    if(cur==n+1)

    {

        if(sum==0)

        {

            tmp[cnt]='\0';

            strcpy(num[cas++],tmp);

        }

        return ;

    }

    for(int i=0; i<3; i++)

    {

        if(i==0)

        {

            tmp[cnt]='+';

            if(cur<10)

            {

                tmp[cnt+1]=cur+'0';

                DFS(cur+1,sum+cur,cnt+2,cur,1);

            }

            else

            {

                tmp[cnt+1]=cur/10+'0';

                tmp[cnt+2]=cur%10+'0';

                DFS(cur+1,sum+cur,cnt+3,cur,1);



            }

        }

        else if(i==1)

        {

            tmp[cnt]='-';

            if(cur<10)

            {

                tmp[cnt+1]=cur+'0';

                DFS(cur+1,sum-cur,cnt+2,cur,2);

            }

            else

            {

                tmp[cnt+1]=cur/10+'0';

                tmp[cnt+2]=cur%10+'0';

                DFS(cur+1,sum-cur,cnt+3,cur,2);

            }

        }

        else

        {

            tmp[cnt]='.';

            if(cur<10)

            {

                tmp[cnt+1]=cur+'0';

                if(flag==1) DFS(cur+1,sum-pre+pre*10+cur,cnt+2,pre*10+cur,flag);

                else DFS(cur+1,sum+pre-pre*10-cur,cnt+2,pre*10+cur,flag);

            }

            else

            {

                tmp[cnt+1]=cur/10+'0';

                tmp[cnt+2]=cur%10+'0';

                if(flag==1) DFS(cur+1,sum-pre+pre*100+cur,cnt+3,pre*100+cur,flag);

                else DFS(cur+1,sum+pre-pre*100-cur,cnt+3,pre*100+cur,flag);

            }

        }

    }

}



int main()

{

    int i,j;

    while(scanf("%d",&n)!=EOF)

    {

        cas=0;

        tmp[0]='1';

        DFS(2,1,1,1,1);

        for(i=0; i<min(cas,20); i++)

        {

            printf("%c",num[i][0]);

            for(j=1; num[i][j]; j++)

                if(num[i][j-1]>='0' && num[i][j-1]<='9' && num[i][j]>='0' && num[i][j]<='9') printf("%c",num[i][j]);

                else printf(" %c",num[i][j]);

            puts("");

        }

        printf("%d\n",cas);

    }

    return 0;

}
View Code

 

POJ  1111 Image Perimeters
http://poj.org/problem?id=1111
题意:读题很久很久。。。还是没懂
         求一个中心X,所能涉及的最远区域所构成的图形周长(八个方向),这里周长所围的是一个矩形。
分析:dfs~~~

#include<stdio.h>

#include<string.h>

const int MN=50;



int row[]={-1,1,0,0,-1,-1,1,1};

int col[]={0,0,-1,1,-1,1,-1,1};



char num[MN][MN];

bool vis[MN][MN];

int n,m;

int sum;



void DFS(int x,int y)

{

    vis[x][y]=1;

    for(int i=0;i<8;i++)

    {

        int xx=x+row[i];

        int yy=y+col[i];

        if((xx==0 || yy==0 || xx>n || yy>m))

        {//刚开始i<4在外面这括号,这样对于下面那组数据过不去

          //因为(3,2)这个点是X,从(1,1)斜着过去,无法continue,导致sum多加了

            if(i<4) sum++;

            continue;

        }

        if(num[xx][yy]!='X' && i<4) sum++;

        else if(num[xx][yy]=='X' && vis[xx][yy]==0)

        {

            DFS(xx,yy);

        }

    }

}



int main()

{

    int x,y;

    while(scanf("%d%d%d%d",&n,&m,&x,&y))

    {

        if(n+m+x+y==0) break;

        memset(vis,0,sizeof(vis));

        //memset(num,0,sizeof(num);/////////

        for(int i=1;i<=n;i++)

        {

           scanf("%s",num[i]+1);

        }

        sum=0;

        DFS(x,y);

        printf("%d\n",sum);

    }

    return 0;

}

/*

3 3 1 2

.X.

X.X

.X.

2 2 2 2

XX

XX

*/
View Code

 

 POJ 1416 Shredding Company
http://poj.org/problem?id=1416
题意:给你两个数,将第二个数重新组合其结果最接近第一个数的结果是多少,其组合方式是所有位进行相加或合并
        

#include<stdio.h>

#include<string.h>

const int MN=100;

char s[MN];

char str[MN];

char tmp[MN];

int n;

int ans;

int len;

int flag;



void DFS(int cur,int sum,int pre,int cnt)

{

    if(cur==len)

    {

        if(sum<=n)

        {

            if(sum>ans)

            {

                flag=1;

                ans=sum;

                tmp[cnt]='\0';

                strcpy(str,tmp);

            }

            else if(sum==ans)

            {

                flag=2;

            }

        }

        return ;

    }

    for(int i=0;i<=1;i++)

    {

        if(i==0)

        {

            tmp[cnt]=' ';

            tmp[cnt+1]=s[cur];

            DFS(cur+1,sum+s[cur]-'0',s[cur]-'0',cnt+2);

        }

        else

        {

            tmp[cnt]=s[cur];

            DFS(cur+1,sum-pre+pre*10+(s[cur]-'0'),pre*10+(s[cur]-'0'),cnt+1);

        }

    }

}



int main()

{

    int i,j;

    while(scanf("%d%s",&n,s))

    {

        if(n==0 && strcmp(s,"0")==0) break;

        flag=0;

        ans=-1;

        len=strlen(s);

        ans=0;

        tmp[0]=s[0];

        DFS(1,s[0]-'0',s[0]-'0',1);

        if(flag==0) printf("error\n");

        else if(flag==2) printf("rejected\n");

        else

        {

            printf("%d",ans);

            printf(" %s",str);

            printf("\n");

        }

    }

    return 0;

}
View Code

 

POJ 3187 Backward Digit Sums
http://poj.org/problem?id=3187
题意:

 3   1   2   4
4 3 6
7 9
16 输入和结果,以及个数的长度,输出第一行的数

分析:搜索+杨辉三角。 由杨辉三角性质可知当,每个数相加的次数就是c[i][j],所以枚举的时候直接当前值j*c[n][cur]

#include<stdio.h>

#include<string.h>



int num[100];

int ans[100];

int vis[100];

int x[20][20];



int flag;

int n,m;



void DFS(int cur,int sum)

{

    if(flag==1)  return ;

    if(cur==n+1)

    {

        if(sum==m)

        {

            flag=1;

            memcpy(ans+1,num+1,sizeof(int)*n);

            return;

        }

        return ;

    }

    for(int j=1; j<=n; j++)

    {

        if(flag==1) return ;

        if(vis[j]==0)

        {

            vis[j]=1;

            num[cur]=j;

            if(cur==1 || cur==n)

                DFS(cur+1,sum+j);

            else DFS(cur+1,sum+j*x[n][cur]);

            vis[j]=0;

        }

    }

}



void init()

{

    for(int i=1; i<=10; i++)

    {

        x[i][1]=x[i][i]=1;

        for(int j=1; j<=i-1; j++)

        {

             x[i][j]=x[i-1][j-1]+x[i-1][j];

        }

    }

    //printf("%d",x[10][1]);

}



int main()

{

    int i,j;

    init();

    while(scanf("%d%d",&n,&m)!=EOF)

    {

        memset(vis,0,sizeof(vis));

        flag=0;

        DFS(1,0);

        printf("%d",ans[1]);

        for(i=2; i<=n; i++)

            printf(" %d",ans[i]);

        printf("\n");

    }

    return 0;

}
View Code

 

POJ 1154 LETTERS
http://poj.org/problem?id=1154

#include<stdio.h>

#include<string.h>

const int MN=100;

const int INF=0x7fffffff;

int vis[MN][MN];

char str[MN][MN];

int flag[200];

int row[]= {-1,1,0,0};

int col[]= {0,0,-1,1};

int ans;

int n,m;





void DFS(int x,int y,int sum)

{

    if(sum>ans) ans=sum;

    vis[x][y]=1;

    flag[str[x][y]]=1;

    for(int i=0; i<4; i++)

    {

        int xx=row[i]+x;

        int yy=col[i]+y;

        if(xx>=1 && yy>=1 && xx<=n && yy<=m && vis[xx][yy]==0 && flag[str[xx][yy]]==0)

        {

            DFS(xx,yy,sum+1);

        }

    }

    vis[x][y]=0;

    flag[str[x][y]]=0;

}



int main()

{

    int i,j;

    while(scanf("%d%d",&n,&m)!=EOF)

    {

        memset(str,0,sizeof(str));

        memset(flag,0,sizeof(flag));

        memset(vis,0,sizeof(vis));

        for(i=1; i<=n; i++)

        {

            scanf("%s",str[i]+1);

        }

        ans=0;

        DFS(1,1,1);

        printf("%d\n",ans);

    }

    return 0;

}
View Code


POJ 1979 Red and Black
http://poj.org/problem?id=1979

#include<stdio.h>

#include<string.h>

const int MN=100;

const int INF=0x7fffffff;

int vis[MN][MN];

char str[MN][MN];

int row[]= {-1,1,0,0};

int col[]= {0,0,-1,1};

int ans;

int n,m;

struct Node

{

    int x,y;

} s;



int DFS(int x,int y)

{

    int sum=0;

    vis[x][y]=1;

    for(int i=0; i<4; i++)

    {

        int xx=x+row[i];

        int yy=y+col[i];

        if(xx>=1 && xx<=n && yy>=1 && yy<=m && vis[xx][yy]==0 && str[xx][yy]=='.')

        {

            sum+=DFS(xx,yy)+1;

        }

    }

    return sum;

}



int main()

{

    int i,j;

    while(scanf("%d%d",&m,&n)!=EOF)

    {

        if(n==0 && m==0) break;

        memset(str,0,sizeof(str));

        memset(vis,0,sizeof(vis));

        for(i=1; i<=n; i++)

        {

            scanf("%s",str[i]+1);

            for(j=1; j<=m; j++)

            {

                if(str[i][j]=='@')

                {

                    s.x=i;

                    s.y=j;

                }

            }

        }

        ans=DFS(s.x,s.y)+1;

        printf("%d\n",ans);

    }

    return 0;

}
View Code

 

 POJ 2157 Maze
http://poj.org/problem?id=2157
题意:判断S能否到G,其中可能包含A~E的门,而打开该门需要找出图中相应的所有打开该门的钥匙
分析:多次dfs,当有新门能打开的话,就重新dfs

#include<stdio.h>

#include<string.h>

const int MN=110;

int vis[MN][MN];

char str[MN][MN];

int n,m;

int A,B,C,D,E;

int row[]= {-1,1,0,0};

int col[]= {0,0,-1,1};

int num1[200];

int num2[200];

int flag;



struct Node

{

    int x,y;

} s,e;



void DFS(int x,int y)

{

    vis[x][y]=1;

    if(x==e.x && y==e.y)

    {

        flag=1;

        return ;

    }

    for(int i=0; i<4; i++)

    {

        int xx=x+row[i];

        int yy=y+col[i];

        if(xx>=1 && xx<=n && yy>=1 && yy<=m && str[xx][yy]!='X' && vis[xx][yy]==0)

        {

            if(str[xx][yy]>='A' && str[xx][yy]<='E') continue;

            DFS(xx,yy);

            num2[str[xx][yy]]++;

        }

    }

}



void work(int i,int j)

{

    if(str[i][j]=='S')

    {

        s.x=i;

        s.y=j;

    }

    else if(str[i][j]=='G')

    {

        e.x=i;

        e.y=j;

    }

    num1[str[i][j]]++;

}



void judge(char c)

{

    for(int i=1; i<=n; i++)

    {

        for(int j=1; j<=m; j++)

        {

            if(str[i][j]==c || str[i][j]==c-'a'+'A')

                str[i][j]='.';

        }

    }

}



int main()

{

    int i,j;

    char c;

    while(scanf("%d%d",&n,&m))

    {

        if(n==0 && m==0) break;

        flag=0;

        memset(num1,0,sizeof(num1));

        memset(num2,0,sizeof(num2));

        memset(vis,0,sizeof(vis));

        for(i=1; i<=n; i++)

        {

            scanf("%s",str[i]+1);

            for(j=1; j<=m; j++)

            {

                work(i,j);

            }

        }

        int sor=1;

        while(sor!=0)

        {

            memset(num2,0,sizeof(num2));

            memset(vis,0,sizeof(vis));

            sor=0;

            DFS(s.x,s.y);

            for(c='a'; c<='e'; c++)

            {

                if(num2[c]==num1[c] && num2[c]!=0)

                {

                    sor=1;

                    judge(c);

                }

            }

            if(flag) break;

        }

        if(flag) printf("YES\n");

        else printf("NO\n");

    }

    return 0;

}
View Code

 

 POJ 2245 http://poj.org/problem?id=2245
题意:按升序输出序列的中所有的六个数
分析:背包思想,放于不放,不要循环,直接判断该cur下,其值要不要储存,循环了的话会重复

#include<stdio.h>

#include<string.h>

#include<algorithm>

using namespace std;



const int MN=30;

int num[MN];

int tmp[MN];

int n;



bool cmp(int a,int b)

{

    return a<b;

}



void DFS(int cur,int cnt)

{

    int i;



    if(cnt==6)

    {

        printf("%d",tmp[0]);

        for(i=1; i<6; i++)

            printf(" %d",tmp[i]);

        puts("");

        return ;

    }

    if(cur==n) return ;

    tmp[cnt]=num[cur];

    DFS(cur+1,cnt+1);

    DFS(cur+1,cnt);

}



int main()

{

    int i,j;

    int flag=0;

    scanf("%d",&n);

    while(1)

    {

        if(n==0) break;



        for(i=0; i<n; i++)

            scanf("%d",&num[i]);



        int t=num[n-1];



        sort(num,num+n,cmp);

        DFS(0,0);

        scanf("%d",&n);

        if(n==0) break;

        else printf("\n");

    }

    return 0;

}
View Code

 

POJ 2248 

http://poj.org/problem?id=2248

题意:输出长度最短的一组数,该组中的每一个数必须由其前面的两个数相加得到
分析:DFS+剪枝

#include<stdio.h>

#include<string.h>

const int MN=110;

const int INF=0x7fffffff;

int num[MN];

int tmp[MN];

int n;

int ans;



void DFS(int cur,int MAX)

{

    if(cur>ans || cur>9) return ;//剪枝

    if(tmp[cur]==n)

    {

        if(cur<ans)

        {

            ans=cur;

            memcpy(num,tmp,sizeof(int)*(cur+1));

        }

        return ;

    }

    for(int j=cur; j>=0; j--)//从大到小搜

    {

        int t=tmp[j]+tmp[cur];

        if(t<=n && t>MAX)//限制条件

        {

            tmp[cur+1]=t;

            DFS(cur+1,t);

        }

    }

}



int main()

{

    while(scanf("%d",&n) && n)

    {

        tmp[0]=1;

        ans=INF;

        DFS(0,1);

        if(ans>100) printf("%d",n);

        printf("%d",num[0]);

        for(int i=1; i<=ans; i++)

            printf(" %d",num[i]);

        puts("");

    }

    return 0;

}
View Code

 

POJ 2436 Disease Management
http://poj.org/problem?id=2436
题意:n头牛,d种病毒,每头牛携带的病毒种类数量不同,问限制在k种病毒的情况下最多可以有几只牛
分析:dfs+位运算
        将病毒选取方式赋为一种状态,将每头牛携带的病毒也赋为一种状态,枚举病毒的选取情况
        然后筛选牛,当牛的状态和病毒状态相融合,将牛筛选出来。

#include<stdio.h>

#include<string.h>

const int MN=40000;

int num[1100];

int n,d,k;

int res;



int work1(int pos)

{

    int cas=0;

    for(int i=0; i<n; i++)

    {

        if(((num[i]&pos)==0))

        {

           cas++;

        }

    }

    return cas;

}



void DFS(int cur,int ans,int cnt)

{

    if(cnt==k)

    {

        int cas=work1(ans);

        if(res<cas) res=cas;

        return ;

    }

    if(cur==d) return ;

    ans^=(1<<cur);

    DFS(cur+1,ans,cnt+1);

    DFS(cur+1,ans^(1<<cur),cnt);

}



int main()

{

    while(scanf("%d%d%d",&n,&d,&k)!=EOF)

    {

        for(int i=0; i<n; i++)

        {

            int t;

            scanf("%d",&t);

            int xx=0;

            for(int j=0; j<t; j++)

            {

                int a;

                scanf("%d",&a);

                xx=xx^(1<<(a-1));

                num[i]=xx;

            }

        }

        res=0;

        DFS(0,(1<<d)-1,0);

        printf("%d\n",res);

    }

    return 0;

}
View Code

若要回溯的话,需要记录回溯的东西的时候,记录的数组应该是局部的,全局的话会在下一个状态的时候把上一个状态的数据给覆盖了

#include<stdio.h>

#include<string.h>

const int MN=400000;

int dp[MN];

int num[1100];

int vis[1100];

int n,d,k;

int res;



int work1(int pos,int rem[])

{

    int cas=0;

    for(int i=0; i<n; i++)

    {

        if(vis[i]==0 && ((num[i]&pos)==0))

        {

            vis[i]=1;

            rem[cas++]=i;

        }

    }

    return cas;

}



void work2(int cas,int rem[])

{

    for(int i=0; i<cas; i++)

    {

        vis[rem[i]]=0;

    }

}



void DFS(int cur,int ans,int cnt,int sum)

{

    if(cnt==k)

    {

        if(res<sum) res=sum;

        return ;

    }

    int rem[1100];

    int MAX=0;

    if(cur==d) return ;

    ans^=(1<<cur);

    int cas=work1(ans,rem);

    DFS(cur+1,ans,cnt+1,sum+cas);

    if(MAX<sum) MAX=sum;

    work2(cas,rem);

    DFS(cur+1,ans^(1<<cur),cnt,sum);

}



int main()

{

    while(scanf("%d%d%d",&n,&d,&k)!=EOF)

    {

        memset(dp,-1,sizeof(dp));

        memset(vis,0,sizeof(vis));

        for(int i=0; i<n; i++)

        {

            int t;

            scanf("%d",&t);

            int xx=0;

            for(int j=0; j<t; j++)

            {

                int a;

                scanf("%d",&a);

                xx=xx^(1<<(a-1));

                num[i]=xx;

            }

        }

        res=0;

        DFS(0,(1<<d)-1,0,0);

        printf("%d\n",res);

    }

    return 0;

}
View Code

 

 POJ 1077 Eight

http://poj.org/problem?id=1077

题意:九宫格,问最少通过多少次移动能将,九个数字的位置按照顺序排列好
分析:BFS+康托展示
        单向BFS POJ超时,双向BFS速度很快,通过这道题学到了康托这个标记方式,就9个数转换成1个数字形成状态(该排列是所有排列种的第几位)
单向BFS(stl超时,用数组模拟队列),front队头=1,rear队尾=2,插入的时候rear++,结束的时候front++,判断while(front<rear)

#include<stdio.h>

#include<string.h>

#include<string>

#include<iostream>

#include<queue>

using namespace std;



int row[]={-1,1,0,0};

int col[]={0,0,-1,1};

int fac[20];

int vis[1000000];

char index[]="udlr";

int e[10],aim;

char path[1000000];

int pre[1000000];



struct Node

{

    int s[10];

    int pos;

    int x,y;//坐标

    int status;//记录康托展开状态

}first,Q[1000000];



int Cantor(int *s)

{

   int sum=0;

   for(int i=0;i<9;i++)

   {

       int cnt=0;

       for(int j=i+1;j<9;j++)

       {

           if(s[i]>s[j]) cnt++;//继续比i位的数字小的个数

       }

       sum+=(cnt*fac[9-i-1]);

   }

   return sum;//返回该顺序是9个数的第多少位

}



void Print(int cur)

{

    if(pre[cur]==-1) return ;

    Print(pre[cur]);

    printf("%c",path[cur]);

}



void BFS()

{

    int front=1,rear=2;

    pre[first.status]=-1;

    vis[first.status]=1;

    Q[front]=first;

    while(front<rear)

    {

        Node t1=Q[front];

        if(t1.status==aim)

        {

            Print(t1.status);

            return;

        }

        Node t2;

        for(int i=0;i<4;i++)

        {

            t2=t1;

            t2.x=t1.x+row[i];

            t2.y=t1.y+col[i];

            if(t2.x>=0 && t2.x<3 && t2.y>=0 && t2.y<3)

            {

                t2.pos=t2.x*3+t2.y;

                t2.s[t1.pos]=t2.s[t2.pos];

                t2.s[t2.pos]=0;

                t2.status=Cantor(t2.s);

                if(!vis[t2.status])

                {

                    vis[t2.status]=1;

                    path[t2.status]=index[i];

                    pre[t2.status]=t1.status;

                    Q[rear]=t2;

                    rear++;

                }

            }

        }

        front++;

    }

    printf("unsolvable\n");

}



void init()

{

    fac[0]=1;

    for(int i=1;i<=9;i++)

    {

        fac[i]=fac[i-1]*i;

    }

    for(int i=1;i<=8;i++) e[i-1]=i;

    e[8]=0;

    aim=Cantor(e);

}



int main()

{

    char s[110];

    int i,j;

    init();//求阶乘

    while(gets(s+1)!=NULL)

    {

        s[0]=' ';

        int x,y;

        x=y=0;

        int cas=0;

        for(i=0;s[i];i++)

        {

            if(s[i]==' ' && s[i+1]!=' ')

            {

                char ch;

                sscanf(&s[i+1],"%c",&ch);

                if(ch=='x')

                {

                    first.pos=cas;

                    first.x=cas/3;

                    first.y=cas%3;

                    first.s[cas++]=0;

                }

                else first.s[cas++]=ch-'0';

                y++;

                if(y==3) x++,y=0;

            }

        }

        first.status=Cantor(first.s);

        memset(vis,0,sizeof(vis));

        BFS();

        puts("");

    }

    return 0;

}
View Code

双向BFS,速度很快,这里出现的问题是 当结束点在起点或终点的时候,由于pre=-1,所以我定义两个数组,pre1代表起点的,pre2终点的

#include<stdio.h>

#include<string.h>

#include<queue>

using namespace std;

const int MN=1000000;

int pre1[MN],pre2[MN],vis[MN];

char path1[MN],path2[MN];

int row[]= {-1,1,0,0};

int col[]= {0,0,-1,1};

char index1[]="udlr";

char index2[]="durl";

int fac[10];



struct Node

{

    int s[10];

    int pos;

    int status;

} first,aim;

queue<Node>Q1,Q2;



int Cantor(int *s)

{

    int sum=0;

    for(int i=0; i<9; i++)

    {

        int cnt=0;

        for(int j=i+1; j<9; j++)

        {

            if(s[i]>s[j]) cnt++;

        }

        sum+=(cnt*fac[9-i-1]);

    }

    return sum+1;

}

void init()

{

    fac[0]=1;

    for(int i=1; i<9; i++) fac[i]=fac[i-1]*i;

    for(int i=0;i<8;i++) aim.s[i]=i+1;

    aim.s[8]=0;

    aim.status=Cantor(aim.s);

    aim.pos=8;

}



void Print1(int Status)

{

    if(pre1[Status]==-1) return ;

    Print1(pre1[Status]);

    printf("%c",path1[Status]);

}



void Print2(int Status)

{

    if(pre2[Status]==-1) return ;

    printf("%c",path2[Status]);

    Print2(pre2[Status]);

}



void solve(int Status)

{

    Print1(Status);

    Print2(Status);

}



void BFS()

{

    int x,y;

    while(!Q1.empty()) Q1.pop();

    while(!Q2.empty()) Q2.pop();

    pre1[first.status]=pre2[aim.status]=-1;

    vis[first.status]=1;

    vis[aim.status]=2;

    Q1.push(first);

    Q2.push(aim);

    if(first.status==aim.status)

    {

        printf("\n");

        return ;

    }

    while(!Q1.empty() && !Q2.empty())

    {

        Node ts1=Q1.front(),ts2;

        Node te1=Q2.front(),te2;

        Q1.pop();Q2.pop();

        for(int i=0; i<4; i++)

        {

            ts2=ts1;

            x=ts1.pos/3+row[i];

            y=ts1.pos%3+col[i];

            if(x>=0 && x<3 && y>=0 && y<3)

            {

                ts2.pos=x*3+y;

                ts2.s[ts1.pos]=ts2.s[ts2.pos];

                ts2.s[ts2.pos]=0;

                ts2.status=Cantor(ts2.s);

                if(!vis[ts2.status])

                {

                    vis[ts2.status]=1;

                    path1[ts2.status]=index1[i];

                    pre1[ts2.status]=ts1.status;

                    Q1.push(ts2);

                }

                else if(vis[ts2.status]==2)

                {

                   path1[ts2.status]=index1[i];

                   pre1[ts2.status]=ts1.status;

                   if(ts2.status==aim.status) Print1(ts2.status);

                   else solve(ts2.status);

                   return ;

                }

            }

            te2=te1;

            x=te1.pos/3+row[i];

            y=te1.pos%3+col[i];

            if(x>=0 && x<3 && y>=0 && y<3)

            {

                te2.pos=x*3+y;

                te2.s[te1.pos]=te2.s[te2.pos];

                te2.s[te2.pos]=0;

                te2.status=Cantor(te2.s);

                if(!vis[te2.status])

                {

                    vis[te2.status]=2;

                    path2[te2.status]=index2[i];

                    pre2[te2.status]=te1.status;

                    Q2.push(te2);

                }

                else if(vis[te2.status]==1)

                {

                    path2[te2.status]=index2[i];

                    pre2[te2.status]=te1.status;

                    if(te2.status==first.status)Print2(te2.status);

                    else solve(te2.status);

                    return ;

                }

            }

        }

    }

    printf("unsolvable");

}



int main()

{

    int i,j;

    init();

    char s[30];

    while(gets(s+1)!=NULL)

    {

        s[0]=' ';

        int cas=0;

        for(i=0; s[i]; i++)

        {

            if(s[i]==' ' && s[i+1]!=' ')

            {

                if(s[i+1]!='x') sscanf(&s[i+1],"%d",&first.s[cas++]);

                else

                {

                    first.pos=cas;

                    first.s[cas++]=0;

                }

            }

        }

        first.status=Cantor(first.s);

        BFS();

        puts("");

    }

    return 0;

}
View Code

  HDU 1043 
这个要从后向前搜,将所有状态都遍历出来,然后再判断vis【status】是否存在来输出

#include<stdio.h>

#include<string.h>

#include<string>

#include<iostream>

#include<queue>

using namespace std;



int row[]= {-1,1,0,0};

int col[]= {0,0,-1,1};

int fac[20];

bool vis[1000000];

char index[]="durl";

int e[10];

char path[1000000];

int pre[1000000];



struct Node

{

    int s[10];

    int pos;

    int x,y;//坐标

    int status;//记录康托展开状态

} first,aim;



queue<Node>Q;



int Cantor(int *s)

{

    int sum=0;

    for(int i=0; i<9; i++)

    {

        int cnt=0;

        for(int j=i+1; j<9; j++)

        {

            if(s[i]>s[j]) cnt++;//继续比i位的数字小的个数

        }

        sum+=(cnt*fac[9-i-1]);

    }

    return sum;//返回该顺序是9个数的第多少位

}



void Print(int cur)

{

    if(pre[cur]==-1) return ;

    printf("%c",path[cur]);

    Print(pre[cur]);

}



void BFS()

{

    while(!Q.empty())  Q.pop();

    aim.x=2;

    aim.y=2;

    aim.pos=8;

    pre[aim.status]=-1;

    Q.push(aim);

    vis[aim.status]=1;

    while(!Q.empty())

    {

        Node t1=Q.front();

        Q.pop();

        Node t2;

        for(int i=0; i<4; i++)

        {

            t2=t1;

            t2.x=t1.x+row[i];

            t2.y=t1.y+col[i];

            if(t2.x>=0 && t2.x<3 && t2.y>=0 && t2.y<3)

            {

                t2.pos=t2.x*3+t2.y;

                t2.s[t1.pos]=t2.s[t2.pos];

                t2.s[t2.pos]=0;

                t2.status=Cantor(t2.s);

                if(!vis[t2.status])

                {

                    vis[t2.status]=1;

                    path[t2.status]=index[i];

                    pre[t2.status]=t1.status;

                    Q.push(t2);

                }

            }

        }

    }

}



void init()

{

    fac[0]=1;

    for(int i=1; i<=9; i++)

    {

        fac[i]=fac[i-1]*i;

        // printf("%d ",fac[i]);

    }

    for(int i=1; i<=8; i++) aim.s[i-1]=i;

    aim.s[8]=0;

    aim.status=Cantor(aim.s);

    //printf("%d ",aim);

}



int main()

{

    char s[110];

    int i,j;



    init();//求阶乘

    BFS();

    while(gets(s+1)!=NULL)

    {

        s[0]=' ';

        int x,y;

        x=y=0;

        int cas=0;

        for(i=0; s[i]; i++)

        {

            if(s[i]==' ' && s[i+1]!=' ')

            {

                char ch;

                sscanf(&s[i+1],"%c",&ch);

                if(ch=='x')

                {

                    first.pos=cas;

                    first.x=cas/3;

                    first.y=cas%3;

                    first.s[cas++]=0;

                }

                else first.s[cas++]=ch-'0';

                y++;

                if(y==3) x++,y=0;

            }

        }

        first.status=Cantor(first.s);

        if(vis[first.status])

        {

            Print(first.status);

             puts("");

        }

        else  printf("unsolvable\n");

       

    }

    return 0;

}
View Code

 

 POJ  1186  方程的解数
http://poj.org/problem?id=1186
分析:求解的个数,由于未知数x只有6个,所以将他对半,让左半部分等于又半部分,dfs1搜索左半部分取得值得个数,dfs2搜索又半部分
         由于其值很大,又需要记录其状态,所以用hash来搞定,取余法

#include<stdio.h>

#include<string.h>

const int MN=4000000;

int k[10],p[10];

bool vis[MN];

int hash[MN];

int num[MN];

int M,n;

int Mid;

int ans;



int locate(int s)

{

    int pos;

    if(s<0) pos=(-s)%MN;

    else pos=s%MN;

    while(vis[pos] && hash[pos]!=s)

        if(++pos>=MN) pos-=MN;

    return pos;

}



void DFS_left(int cur,int sum)

{

    if(cur==Mid)

    {

        int pos=locate(sum);

        num[pos]++;

        vis[pos]=1;

        hash[pos]=sum;

        return ;

    }

    for(int i=1; i<=M; i++)

    {

        int tmp=k[cur];

        for(int j=0; j<p[cur]; j++)

        {

            tmp*=i;

        }

        DFS_left(cur+1,sum+tmp);

    }

}



void DFS_right(int cur,int sum)

{

    if(cur==n)

    {

        sum=-sum;

        int pos=locate(sum);

        if(hash[pos]==sum)

             ans+=num[pos];

        return ;

    }

    for(int i=1; i<=M; i++)

    {

        int tmp=k[cur];

        for(int j=0; j<p[cur]; j++)

        {

            tmp*=i;

        }

        DFS_right(cur+1,sum+tmp);

    }

}



int main()

{

    int i;

    while(scanf("%d",&n)!=EOF)

    {

        scanf("%d",&M);

        for(i=0; i<n; i++)

        {

            scanf("%d%d",&k[i],&p[i]);

        }

        Mid=n/2;

        ans=0;

        memset(num,0,sizeof(num));

        memset(vis,0,sizeof(vis));

        memset(hash,-1,sizeof(hash));

        DFS_left(0,0);

        DFS_right(Mid,0);

        printf("%d\n",ans);

    }

    return 0;

}
View Code

 

 

  

你可能感兴趣的:(搜索)