ida* 的一些题 ida*小结

         这些题都是http://www.cnblogs.com/ambition/archive/2011/07/25/search_plus.html  里的。。我的一些代码也参考了里边的代码

HDU 1043 Eight      话说是一道涉及到人生完整不完整的题 八数码

      判断有没有解:求出所给状态的逆序数m,如果同是奇数则无解,偶数则有解。  why?  因为移动一次逆序数 加2 或 减2 (我也不会证,就是自己试了下,发现是)

   在我的程序中空位用0表示

   方法一: A*

   估价函数: 计算当前状态到目标状态的 曼哈顿距离。 因为移动一次,曼哈顿距离 加1或减1,所以直接返回曼哈顿距离

   状态存储: 采用 康托 法。 把一个图转化成一个数。

      判重:   把图转化为 康托数后,用个 hash       9!=362880

   然后就是bfs了。

   用一个pre 数组记录路径

        A* 是要用优先队列了,无奈于对堆不太熟练,于是用了STL

下面对程序的执行过程简略介绍:

   对于每个结点存 了当前的图G(用了康托后就是一个数, (可以不用康托数,直接开个数组 记录整个图)我的第二个程序就是这样的。

                                  当前已走多少步step,

                                 当前状态到目标状态的曼哈顿距离dis,

                                则预计至少h步到目标状态(h=step+dis)

 优先队列就是根据 按上从小到大排序的      (STL 中默认是从大到小,所以要自己写个比较函数,或者重载运算符(我是重载运算符的)

        1.读入数据:

         如果是x换成0

   2.判断逆序数是否为奇数

            奇数:无解

            偶数:继续

   3.bfs

                1.起点入队

      2.向四个方向 搜索,计算 step,dis,h

                3.判重

          不重,入队,设置其前趋

      4.遇到终点 则结束。

    输出结果,是倒着的,放在数组里。

A*代码:

View Code
  1 #include<iostream>
  2 #include<queue>
  3 using namespace std;
  4 int vis[362885];
  5 int factor[]={1,1,2,6,24,120,720,5040,40320,362880,3628800}; //用于康托
  6 int mx[]={1,0,0,-1};   //四个移动方向的控制
  7 int my[]={0,-1,1,0};
  8 char x[11],ans[362885];//由于BFS搜得的结果在是倒着的。所以先把移动序列正着存放在ans中
  9 char cov[]={'d','l','r','u'};   
 10 int na;
 11 const int N=9;
 12 struct node
 13 {
 14     int step;//到G这个状态已经走了step步
 15     int dis;//用估价函数所得
 16     int h;  //h=step+dis 用于优先队列的优先级
 17     int G;  //当前状态,是一个数,用反康托算法展开就可以得到这个状态
 18 };
 19 struct s
 20 {
 21     int sum;  
 22     int d;   //移动方向
 23 }pre[362885];//用于记录当前状态的的前驱
 24 priority_queue<node> Q;
 25 int Start,End;
 26 bool operator<(const node &t1,const node &t2)
 27 {
 28     if(t1.h==t2.h)
 29         return t1.step<t2.step;
 30     else
 31         return t1.h>t2.h;
 32 }
 33 int cantor(char *y,int n)    //康托 把这个序列变成一个数
 34 {
 35     int sum=0,i,j,cnt;
 36     for(i=0;i<n;i++)
 37     {
 38         cnt=0;
 39         for(j=i+1;j<n;j++)
 40             if(y[j]<y[i])
 41                 cnt++;
 42         sum+=factor[n-i-1]*cnt;
 43     }
 44     return sum;
 45 }           
 46 void fcantor(char *y,int n,int m)  //反康托,把一个数n变成一个排列
 47 {
 48     int i,j,cnt,k;
 49     bool vis[15]={0};
 50     for(i=0;i<m;i++)
 51     {
 52         k=n/factor[m-i-1];
 53         n%=factor[m-i-1];
 54         cnt=0;
 55         for(j=1;j<=m;j++)
 56         {
 57             if(!vis[j])
 58                 cnt++;
 59             if(cnt==k+1)
 60                 break;
 61         }
 62         y[i]=j;
 63         vis[j]=true;
 64     }
 65 }       
 66 int inverse_number(char *y,int m)   //求逆序数 
 67 {
 68     int i,j,cnt=0;
 69     for(i=1;i<m;i++)
 70     {
 71         if(y[i]==N)continue;
 72         for(j=i-1;j>=0;j--)
 73             if(y[j]>y[i]&&y[j]!=N)
 74                 cnt++;
 75     }
 76     return !(cnt&1);
 77 }
 78 int man_dis(char *y,int n)  // 曼哈顿距离
 79 {
 80     int i,j,tx,ty,dis=0;
 81     for(i=0;i<3;i++)
 82         for(j=0;j<3;j++)
 83         {
 84             if(y[i*3+j]==9)continue;
 85             tx=(y[i*3+j]-1)/3;
 86             ty=(y[i*3+j]-1)%3;
 87             dis+=abs(tx-i)+abs(ty-j);
 88         }
 89         return dis;
 90 }
 91 void bfs()
 92 {
 93     while(!Q.empty())Q.pop();
 94     memset(vis,0,sizeof(vis));
 95     node t,p;
 96     t.step=0; t.G=Start; t.dis=0;
 97     Q.push(t); 
 98     vis[Start]=true;
 99     pre[Start].d=-1;pre[Start].sum=-1;
100     char y[11];
101     int fx,fy,tx,ty,i;
102     while(!Q.empty())
103     {
104         t=Q.top();
105         Q.pop();
106         fcantor(y,t.G,N);
107         for(i=0;i<N;i++)
108             if(y[i]==9)
109                 break;
110         fx=i/3; fy=i%3;
111         for(i=0;i<4;i++)      //四个方向 广搜
112         {
113             p=t;
114             tx=fx+mx[i];
115             ty=fy+my[i];
116             if(tx<0||ty<0||tx>=3||ty>=3)
117                 continue;
118             swap(y[fx*3+fy],y[tx*3+ty]);     //移动
119             p.G=cantor(y,N);                //转化为一个数
120             p.dis=man_dis(y,N);              //估价函数
121             p.step++;
122             p.h=p.step+p.dis;
123             if(!vis[p.G])                  //判重
124             {
125                 vis[p.G]=true;
126                 Q.push(p);
127                 pre[p.G].sum=t.G;
128                 pre[p.G].d=i;
129             }
130             if(p.G==0)
131                 return;
132             swap(y[fx*3+fy],y[tx*3+ty]);          //不要忘了换回来
133         }
134     }
135 }
136 int main()
137 {
138     //freopen("input.txt","r",stdin);
139     int i;
140     while(true)
141     {
142         for(i=0;i<N;i++)
143         {
144             if(!(cin>>x[i]))
145                 return 0;
146             if(x[i]=='x')
147                 x[i]=N;
148             else
149                 x[i]-='0';
150 
151         }
152         Start=cantor(x,N);
153         End=0;
154         if(inverse_number(x,N))
155         {
156             bfs();
157             na=0;
158             while(pre[End].sum!=-1)
159             {
160                 ans[na++]=cov[pre[End].d];
161                 End=pre[End].sum;
162             }
163             for(i=na-1;i>=0;i--)
164                 cout<<ans[i];
165         }
166         else 
167             cout<<"unsolvable";
168         cout<<endl;
169     }
170     return 0;
171 }

存图时不用康托数,直接保存整个图的代码。这样的发处是,每次出队后,不用把数把解为图了

View Code
  1 #include<iostream>
  2 #include<queue>
  3 using namespace std;
  4 int vis[362885];
  5 int factor[]={1,1,2,6,24,120,720,5040,40320,362880,3628800};
  6 int mx[]={1,0,0,-1};
  7 int my[]={0,-1,1,0};
  8 char x[11],ans[362885];
  9 char cov[]={'d','l','r','u'};
 10 int na;
 11 const int N=9;
 12 struct node
 13 {
 14     int step;
 15     int dis;
 16     int h;
 17     char G[11];
 18 };
 19 struct s
 20 {
 21     int sum;
 22     int d;
 23 }pre[362885];
 24 priority_queue<node> Q;
 25 int Start,End;
 26 bool operator<(const node &t1,const node &t2)
 27 {
 28     if(t1.h==t2.h)
 29         return t1.step<t2.step;
 30     else
 31         return t1.h>t2.h;
 32 }
 33 int cantor(char *y,int n)
 34 {
 35     int sum=0,i,j,cnt;
 36     for(i=0;i<n;i++)
 37     {
 38         cnt=0;
 39         for(j=i+1;j<n;j++)
 40             if(y[j]<y[i])
 41                 cnt++;
 42         sum+=factor[n-i-1]*cnt;
 43     }
 44     return sum;
 45 }
 46 void fcantor(char *y,int n,int m)
 47 {
 48     int i,j,cnt,k;
 49     bool vis[15]={0};
 50     for(i=0;i<m;i++)
 51     {
 52         k=n/factor[m-i-1];
 53         n%=factor[m-i-1];
 54         cnt=0;
 55         for(j=1;j<=m;j++)
 56         {
 57             if(!vis[j])
 58                 cnt++;
 59             if(cnt==k+1)
 60                 break;
 61         }
 62         y[i]=j;
 63         vis[j]=true;
 64     }
 65 }
 66 int inverse_number(char *y,int m)
 67 {
 68     int i,j,cnt=0;
 69     for(i=1;i<m;i++)
 70     {
 71         if(y[i]==N)continue;
 72         for(j=i-1;j>=0;j--)
 73             if(y[j]>y[i]&&y[j]!=N)
 74                 cnt++;
 75     }
 76     return !(cnt&1);
 77 }
 78 int man_dis(char *y,int n)
 79 {
 80     int i,j,tx,ty,dis=0;
 81     for(i=0;i<3;i++)
 82         for(j=0;j<3;j++)
 83         {
 84             if(y[i*3+j]==9)continue;
 85             tx=(y[i*3+j]-1)/3;
 86             ty=(y[i*3+j]-1)%3;
 87             dis+=abs(tx-i)+abs(ty-j);
 88         }
 89         return dis;
 90 }
 91 void bfs()
 92 {
 93     while(!Q.empty())Q.pop();
 94     memset(vis,0,sizeof(vis));
 95     node t,p;
 96     t.step=0;  t.dis=0;
 97     memcpy(t.G,x,sizeof(x));
 98     Q.push(t); 
 99     vis[Start]=true;
100     pre[Start].d=-1;pre[Start].sum=-1;
101     char y[11];
102     int fx,fy,tx,ty,i,fn,tn;
103     while(!Q.empty())
104     {
105         t=Q.top();
106         Q.pop();
107         fn=cantor(t.G,N);
108         //cout<<t.dis<<" "<<t.step<<" "<<t.h<<endl;
109         for(i=0;i<N;i++)
110             if(t.G[i]==9)
111                 break;
112         fx=i/3; fy=i%3;
113         for(i=0;i<4;i++)
114         {
115             p=t;
116             tx=fx+mx[i];
117             ty=fy+my[i];
118             if(tx<0||ty<0||tx>=3||ty>=3)
119                 continue;
120             p.G[fx*3+fy]=p.G[tx*3+ty];
121             p.G[tx*3+ty]=9;
122             tn=cantor(p.G,N);
123             p.dis=man_dis(p.G,N);
124             p.step++;
125             p.h=p.step+p.dis;
126             if(!vis[tn])
127             {
128                 vis[tn]=true;
129                 Q.push(p);
130                 pre[tn].sum=fn;
131                 pre[tn].d=i;
132             }
133             if(tn==0)
134                 return;
135         }
136     }
137 }
138 int main()
139 {
140     //freopen("input.txt","r",stdin);
141     int i;
142     while(true)
143     {
144         for(i=0;i<N;i++)
145         {
146             if(!(cin>>x[i]))
147                 return 0;
148             if(x[i]=='x')
149                 x[i]=N;
150             else
151                 x[i]-='0';
152 
153         }
154         /*cout<<cantor(x,N)<<endl;
155         int t;
156         cout<<"input t to x\n";
157         cin>>t;
158         fcantor(x,t,N);
159         for(i=0;i<N;i++)
160             cout<<(int)x[i];
161         cout<<endl;*/

162         //cout<<inverse_number(x,N)<<endl;
163         Start=cantor(x,N);
164         End=0;
165         if(inverse_number(x,N))
166         {
167             bfs();
168             na=0;
169             while(pre[End].sum!=-1)
170             {
171                  ans[na++]=cov[pre[End].d];
172                  End=pre[End].sum;
173              }
174             for(i=na-1;i>=0;i--)
175                 cout<<ans[i];
176         }
177         else 
178             cout<<"unsolvable";
179         cout<<endl;
180     }
181     return 0;
182 }

 

 

方法二:

      先从终点向起点搜出所有状态,问哪个就输出哪个。

View Code
  1 //八数码
  2 #include<iostream>
  3 #include<queue>
  4 using namespace std;
  5 char x[11];
  6 int factor[]={1,1,2,6,24,120,720,5040,40320,362880,3628800};
  7 bool vis[362881];
  8 int ans;
  9 #define N 9
 10 int mx[]={0,0,1,-1};  
 11 int my[]={1,-1,0,0};
 12 struct
 13 {
 14     int d;
 15     int sum;
 16 }pre[362881];
 17 char cov[]={'l','r','u','d'}; //这四个方向都设反了。因为是倒搜
 18 int cantor(char *y,int n)    /*将全排列转换为一个数*/
 19 {
 20     int i,j,cnt,sum=0;
 21     for(i=0;i<n;i++)
 22     {
 23         cnt=0;
 24         for(j=i+1;j<n;j++)
 25             if(y[j]<y[i])
 26                 cnt++;
 27         sum+=factor[n-i-1]*cnt;
 28     }
 29     return sum;
 30 }
 31 struct node
 32 {
 33     char G[3][3];
 34     int x,y,ct;
 35 }Start;
 36 queue<node> Q;
 37 int inverse_number(char *y,int m)
 38 {
 39     int i,j,cnt=0;
 40     for(i=1;i<m;i++)
 41     {
 42         if(y[i]==N)continue;
 43         for(j=i-1;j>=0;j--)
 44             if(y[j]>y[i]&&y[j]!=N)
 45                 cnt++;
 46     }
 47     return !(cnt&1);
 48 }
 49 void bfs()
 50 {
 51     memset(vis,0,sizeof(vis));
 52     memset(pre,-1,sizeof(pre));
 53     int i,j,tn,tx,ty;
 54     node t;
 55     for(i=0;i<3;i++)
 56         for(j=0;j<3;j++)
 57             t.G[i][j]=i*3+j+1;
 58     t.x=2,t.y=2;t.ct=0;
 59     while(!Q.empty())Q.pop();
 60     Q.push(t);
 61     vis[0]=true;
 62     while(!Q.empty())
 63     {
 64         t=Q.front();Q.pop();
 65         node p;
 66         for(i=0;i<4;i++)
 67         {
 68             tx=t.x+mx[i];
 69             ty=t.y+my[i];
 70             if(tx<0||ty<0||tx>=3||ty>=3)
 71                 continue;
 72             p=t;
 73             p.G[p.x][p.y]=p.G[tx][ty];
 74             p.G[tx][ty]=9;
 75             p.x=tx;p.y=ty;
 76             tn=cantor(p.G[0],9);
 77             p.ct=tn;
 78             if(vis[tn])continue;
 79             vis[tn]=true;
 80 
 81             Q.push(p);
 82             pre[tn].d=i;
 83             pre[tn].sum=t.ct;
 84         }
 85     }
 86 }
 87 int main()
 88 {
 89     //freopen("input.txt","r",stdin);
 90     int i,j;
 91     bfs();
 92     while(true)
 93     {
 94         for(i=0;i<3;i++)
 95             for(j=0;j<3;j++)
 96             {
 97                 if(!(cin>>Start.G[i][j]))
 98                     return 0;
 99 
100                 if(Start.G[i][j]=='x')
101                 {
102                     Start.x=i;
103                     Start.y=j;
104                     Start.G[i][j]=9;
105                 }
106                 else
107                     Start.G[i][j]-='0';
108 
109             }
110 
111 
112             if(!inverse_number(Start.G[0],9))
113             {
114                 cout<<"unsolvable"<<endl;
115                 continue;
116             }
117             ans=cantor(Start.G[0],N);
118             while(ans!=0)
119             {
120                 cout<<cov[pre[ans].d];
121                 ans=pre[ans].sum;
122             }
123             cout<<endl;
124     }
125     return 0;
126 }

 

 

HDU 1667 The Rotation Game

   这个用 ida*

         1.估价函数 

         要保证中间四个数一样,所以统计一下中间 至少 还需移动几次就能让数字相同。因为第移动一次只会 增加或减少一个数。

   2.存储状态,基本不用,只要一个数组就行了。dfs返回时把状态改回来。

   3.判 重也不用啦。  原因是,如果重复的起很多步肯定比没重复走的用的步数少。

   4.用一个数组记录路径

   5.预先写好移动的函数。

解决在dfs中 8方向函数调用问题

      当然,一个一个写也可以

看看这个吧:void (*pm[4])(int s[N][N],int x);//方便函数批量调用

 

   

代码在此:

View Code
  1 #include<iostream>
  2 using namespace std;
  3 int G[7][7];
  4 #define N 7
  5 int deep;
  6 void (*pm[4])(int s[N][N],int x);//方便函数批量调用
  7 int mx[]={2,4};
  8 int ans[100000],bs[10000],cs;
  9 char opt[4][2]={'A','B','C','D','F','E','H','G'};
 10 
 11 //**************移动******************************
 12 void up(int s[N][N],int y)
 13 {
 14     int t=s[0][y];
 15     for(int i=0;i<6;i++)
 16         s[i][y]=s[i+1][y];
 17     s[6][y]=t;
 18 }
 19 void down(int s[N][N],int y)
 20 {
 21     int t=s[6][y];
 22     for(int i=6;i>0;i--)
 23         s[i][y]=s[i-1][y];
 24     s[0][y]=t;
 25 }
 26 void left(int s[N][N],int x)
 27 {
 28     int t=s[x][0];
 29     for(int j=0;j<6;j++)
 30         s[x][j]=s[x][j+1];
 31     s[x][6]=t;
 32 }
 33 void right(int s[N][N],int x)
 34 {
 35     int t=s[x][6];
 36     for(int j=6;j>0;j--)
 37         s[x][j]=s[x][j-1];
 38     s[x][0]=t;
 39 }
 40 //******************移动结束***********************************
 41 
 42 
 43 
 44 //**************估价函数**************************************
 45 int check(int s[N][N])
 46 {
 47     s[3][3]=0;                       //把这个设为0,下边就可以用循环统计每个数字出现的个数了
 48     int i,j,cnt[4]={0};
 49     for(i=2;i<=4;i++)
 50         for(j=2;j<=4;j++)
 51             cnt[s[i][j]]++;
 52     return max(max(cnt[1],cnt[2]),cnt[3]);  //返加了其中出现的最多次
 53 }
 54 //**************估价函数结束**************************************
 55 
 56 
 57 //***********dfs*****************************
 58 bool dfs(int step)
 59 {
 60     int h=8-check(G),tj;
 61     if(h==0){cs=step;return true;}
 62     if(step+h>deep)return false;
 63     for(int i=0;i<4;i++)
 64         for(int j=0;j<2;j++)
 65         {
 66             tj=j;
 67             if(i>=2)tj=2-j-1;
 68             pm[i](G,mx[tj]);
 69             ans[step]=i;
 70             bs[step]=tj;
 71             if(dfs(step+1))
 72                 return true;
 73             pm[(i+2)%4](G,mx[tj]);
 74         }
 75         return false;
 76 }
 77 int main()
 78 {
 79     //freopen("input.txt","r",stdin);
 80     int i,j;
 81     while(cin>>G[0][2]&&G[0][2])
 82     {
 83 //*******************************************************
 84 //      input data
 85         cin>>G[0][4];
 86         cin>>G[1][2]>>G[1][4];
 87         for(i=0;i<7;i++)
 88             cin>>G[2][i];
 89         cin>>G[3][2]>>G[3][4];
 90         for(i=0;i<7;i++)
 91             cin>>G[4][i];
 92         cin>>G[5][2]>>G[5][4]>>G[6][2]>>G[6][4];    
 93 //***************inpute end********************************
 94 
 95 
 96 //*************set point**************************************
 97         pm[0]=up;
 98         pm[1]=right;
 99         pm[2]=down;
100         pm[3]=left;
101 //***********************************************************
102 
103 
104 //*****************control dfs**********************************
105         deep=8-check(G);
106         if(deep==0)
107 
108             cout<<"No moves needed"<<endl<<G[2][2]<<endl;
109         else
110         {
111             while(!dfs(0))deep++;
112             for(i=0;i<cs;i++)
113                 cout<<opt[ans[i]][bs[i]];
114             cout<<endl<<G[2][2]<<endl;
115         }
116     }
117     return 0;
118 }

 

 

HDU 2234 无题I

ida*

     1.估价函数

       计算每一行至少需要到步数能移成四个一样的数字,并累加起来得到s1

                    计算每一列至少需要到步数能移成四个一样的数字,并累加起来得到s2

       s=min(s1,s2)

                    返回 (s+3)/4                原因在于   每移动一次能改变四个数字 所以除以4  

 2。写好四个移动函数,ida*搜索就行了。

 代码在此

View Code
  1 #include<iostream>
  2 #include<cstring>
  3 #include<stdio.h>
  4 #define inf 100000
  5 using namespace std;
  6 int block[4][4];
  7 int ans;
  8 void Left(int (*b)[4],int row)
  9 {
 10     int t=b[row][0],i;
 11     for(i=0;i<3;i++)
 12         b[row][i]=b[row][i+1];
 13     b[row][3]=t;
 14 }
 15 void Right(int (*b)[4],int row)
 16 {
 17     int t=b[row][3],i;
 18     for(i=3;i>0;i--)
 19         b[row][i]=b[row][i-1];
 20     b[row][0]=t;
 21 }
 22 void Up(int (*b)[4],int col)
 23 {
 24     int i,t=b[0][col];
 25     for(i=0;i<3;i++)
 26         b[i][col]=b[i+1][col];
 27     b[3][col]=t;
 28 }
 29 
 30 void Down(int (*b)[4],int col)
 31 {
 32     int i,t=b[3][col];
 33     for(i=3;i>0;i--)
 34         b[i][col]=b[i-1][col];
 35     b[0][col]=t;
 36 }
 37 int h(int (*b)[4])
 38 {
 39     int i,j,tmp,ans=inf;
 40     int hs[5],cnt;
 41     tmp=0;
 42     for(i=0;i<4;i++)
 43     {
 44         cnt=0;
 45         memset(hs,0,sizeof(hs));
 46         for(j=0;j<4;j++)
 47             hs[b[i][j]]++;
 48         for(j=1;j<=4;j++)
 49             cnt=max(cnt,hs[j]);
 50             
 51             tmp+=4-cnt;
 52     }
 53     ans=min(ans,tmp);
 54     tmp=0;
 55     for(j=0;j<4;j++)
 56     {
 57         cnt=0;
 58         memset(hs,0,sizeof(hs));
 59         for(i=0;i<4;i++)
 60             hs[b[i][j]]++;
 61         for(i=1;i<=4;i++)
 62             cnt=max(cnt,hs[i]);
 63             tmp+=4-cnt;
 64     }
 65     ans=min(ans,tmp);
 66     return (ans+3)/4;
 67 }
 68 
 69 bool dfs(int step)
 70 {
 71     int hz=h(block);
 72     if(hz==0)return true;
 73     if(step+hz>ans)
 74         return false;
 75     int i;
 76     for(i=0;i<4;i++)
 77     {
 78         Left(block,i);
 79         if(dfs(step+1))return true;
 80         Right(block,i);
 81     }
 82 
 83     for(i=0;i<4;i++)
 84     {
 85         Right(block,i);
 86         if(dfs(step+1))return true;
 87         Left(block,i);
 88     }
 89 
 90     for(i=0;i<4;i++)
 91     {
 92         Up(block,i);
 93         if(dfs(step+1))return true;
 94         Down(block,i);
 95     }
 96 
 97     for(i=0;i<4;i++)
 98     {
 99         Down(block,i);
100         if(dfs(step+1))return true;
101         Up(block,i);
102     }
103     return false;
104 }
105 int main()
106 {
107     //freopen("input.txt","r",stdin);
108     int T,i,j;
109     cin>>T;
110     while(T--)
111     {
112         for(i=0;i<4;i++)
113             for(j=0;j<4;j++)
114                 scanf("%d",&block[i][j]);
115         ans=0;
116         while(ans<=5&&!dfs(0))
117             ans++;
118         if(ans<6)
119             cout<<ans<<endl;
120         else
121             cout<<-1<<endl;
122     }
123     return 0;
124 }

 

HDU 1560 DNA sequence

继续ida*

1.估价函数

    返回 处理到当前状态时,还剩下的最长的字符串的长度。

    检举当前的可能的字符x, x={ATCG}四种。  如果对于所用序列,如果开始是x,则开始指针向的移动,如果没有一样的,则说明当前不可能是x,继续下一个。


代码在此:

View Code
 1 #include<iostream>
 2 #include<string.h>
 3 #include<stdio.h>
 4 using namespace std;
 5 char str[10][10],ans[100];
 6 int N,ns[100];
 7 int len[10];
 8 int step;
 9 char bz[]="AGCT";
10 int h()
11 {
12     int i,p=0;
13     for(i=0;i<N;i++)
14         if(len[i]-ns[i]>p)
15             p=len[i]-ns[i];
16             return p;
17 }
18 bool dfs(int k)
19 {
20     
21     int i,j,ht=h();
22     if(ht==0)return true;
23     if(k+ht>step)
24         return false;
25     int sta[10],top=0;
26     bool flag;
27     for(i=0;i<4;i++)               //枚举当前可能的
28     {
29         flag=false;
30         for(j=0;j<N;j++)
31             if(str[j][ns[j]]==bz[i])
32                 {
33                     flag=true;
34                     ns[j]++;      
35                     sta[top++]=j;
36                }
37         if(flag)
38         if(dfs(k+1))
39             return true;
40         for(j=0;j<top;j++)
41         {
42             ns[sta[j]]--;
43         }
44         top=0;
45     }
46     return false;
47 }
48 int main()
49 {
50     //freopen("input.txt","r",stdin);
51     int T,i;
52     cin>>T;
53     while(T--)
54     {
55         cin>>N;
56         for(i=0;i<N;i++)
57             cin>>str[i];
58         step=0;
59         for(i=0;i<N;i++)
60             len[i]=strlen(str[i]);
61 
62         memset(ns,0,sizeof(ns));
63         while(!dfs(0))
64         {
65             memset(ns,0,sizeof(ns));
66             step++;
67         }
68         cout<<step<<endl;
69     }
70     
71     return 0;
72 }

 

HDU 1813  Escape from Tetris

这题一看没思路啊。结果是字典序枚举指令"east","north","south","west"。  总之是 ida*

1. 估价函数:

      首先,求出各个点到边上的最小步数。  把边界的空点加入队列进行 bfs。用个数组记录下

      然后,所有的空点一起走一步,

      在此过程中,返回这些点中到边上的步数中最大的(即上边用数组记录下的。

View Code
  1 #include<iostream>
  2 #include<stdio.h>
  3 #include<string.h>
  4 #include<vector>
  5 #include<queue>
  6 using namespace std;
  7 int N,sp;
  8 char G[12][12];
  9 int mx[]={0,-1,1,0};
 10 int my[]={1,0,0,-1};
 11 char outstr[4][6]={"east","north","south","west"};
 12 int ans[100];
 13 struct point
 14 {
 15     int x,y;
 16     bool stop;
 17     point(int a=0,int b=0):x(a),y(b){stop=false;}
 18 };
 19 vector<point> start;
 20 queue<point> Q;
 21 bool isedg(int x,int y)
 22 {
 23     if(x==0||x==N-1||y==0||y==N-1)
 24         return true;
 25     return false;
 26 }
 27 int minstep[12][12];
 28 int h()
 29 {
 30     int maxn=0,n=start.size(),i;
 31     for(i=0;i<n;i++)
 32         if(maxn<minstep[start[i].x][start[i].y])
 33             maxn=minstep[start[i].x][start[i].y];
 34     return maxn;
 35 }
 36 bool dfs(int k)
 37 {
 38     int hz=h();
 39     if(hz==0)return true;
 40     if(k+hz>sp)return false;
 41     int i,j,n=start.size(),tx,ty;
 42     vector<point> tmp(start);
 43     bool flag;
 44     for(i=0;i<4;i++)
 45     {
 46         flag=false;
 47         for(j=0;j<n;j++)
 48             if(!start[j].stop)
 49             {
 50             flag=true;
 51             tx=start[j].x+mx[i];
 52             ty=start[j].y+my[i];
 53             if(G[tx][ty]=='1')
 54                 continue;
 55             if(isedg(tx,ty))         //判断是不是到了边上
 56                 start[j].stop=true;
 57             start[j].x=tx;
 58             start[j].y=ty;
 59             }
 60             if(!flag)
 61                 return true;
 62             else
 63             { 
 64                 ans[k]=i;
 65                 if(dfs(k+1))    
 66                    return true;
 67             }
 68         for(int var=0;var<n;var++)
 69             start[var]=tmp[var];
 70     }
 71     return false;
 72 }
 73 void bfs()             //广搜出各个点最少能到边上的距离
 74 {
 75     int i,tx,ty;
 76     point t;
 77     while(!Q.empty())
 78     {
 79         t=Q.front();Q.pop();
 80         for(i=0;i<4;i++)
 81         {
 82             tx=t.x+mx[i];
 83             ty=t.y+my[i];
 84             if(tx>=0&&tx<N&&ty>=0&&ty<N)
 85                 if(G[tx][ty]=='0')
 86                 if(minstep[tx][ty]>minstep[t.x][t.y]+1)
 87                 {
 88                     minstep[tx][ty]=minstep[t.x][t.y]+1;
 89                     Q.push(point(tx,ty));
 90                 }
 91         }
 92     }
 93 
 94 }
 95 int main()
 96 {
 97     //freopen("input.txt","r",stdin);
 98     int i,j;
 99     bool isfirst=true;
100     while(cin>>N)
101     {
102         start.clear();
103         while(!Q.empty())Q.pop();
104         memset(minstep,127,sizeof(minstep));
105         for(i=0;i<N;i++)
106             cin>>G[i];
107         for(i=0;i<N;i++)
108             for(j=0;j<N;j++)
109                 if(G[i][j]=='0')
110                     if(!isedg(i,j))
111                       start.push_back(point(i,j));  //将中间的空点装入数组,以备深搜
112                     else
113                     {
114                         minstep[i][j]=0;          //将边界空点装入队列,以备广搜
115                         Q.push(point(i,j));
116                     }
117         bfs();
118        sp=0;
119        while(!dfs(0))
120            sp++;
121        if(!isfirst)
122            cout<<endl;
123        isfirst=false;
124        for(j=0;j<sp;j++)
125            cout<<outstr[ans[j]]<<endl;
126     }
127     return 0;
128 }

 

  HDU 2918 Tobo or not Tobo

  这个还是ida*

1.估价函数:

     (曼哈顿距离+3)/4         除以4是因为,每转一次会改变四方块,也就是曼哈顿距离会变4

然后我写了顺时针转和逆时针转的函数。

  又把四旋钮的所控制的四个方块,分别存到数组里 

ida*   搜索吧

 

代码在此:

View Code
 1 #include<iostream>
 2 #include<stdio.h>
 3 using namespace std;
 4 int board[10][10];
 5 int lim;
 6 int *p[4][4];
 7 int ans;
 8 void (*rot[2])(int *p[]); 
 9 void AntiClockWise(int *p[])
10 {
11     int t=*p[0],i;
12     for(i=0;i<3;i++)
13         *p[i]=*p[i+1];
14     *p[3]=t;
15 }
16 void ClockWise(int *p[])
17 {
18     int t=*p[3],i;
19     for(i=3;i>0;i--)
20         *p[i]=*p[i-1];
21     *p[0]=t;
22 }
23 void set_point()
24 {
25     rot[0]=ClockWise;
26     rot[1]=AntiClockWise;
27     p[0][0]=&board[0][0]; p[0][1]=&board[0][1]; p[0][2]=&board[1][1]; p[0][3]=&board[1][0];
28     p[1][0]=&board[0][1]; p[1][1]=&board[0][2]; p[1][2]=&board[1][2]; p[1][3]=&board[1][1];
29     p[2][0]=&board[1][0]; p[2][1]=&board[1][1]; p[2][2]=&board[2][1]; p[2][3]=&board[2][0];
30     p[3][0]=&board[1][1]; p[3][1]=&board[1][2]; p[3][2]=&board[2][2]; p[3][3]=&board[2][1];
31 }
32 void show_state()
33 {
34     int i,j;
35     for(i=0;i<3;i++)
36     {
37         for(j=0;j<3;j++)
38             cout<<board[i][j];
39         cout<<endl;
40     }
41     cout<<endl;
42 }
43 int h()
44 {
45     int i,j,tx,ty,s=0;
46     for(i=0;i<3;i++)
47         for(j=0;j<3;j++)
48         {
49             tx=(board[i][j]-1)/3;
50             ty=(board[i][j]-1)%3;
51             s+=abs(i-tx)+abs(j-ty);
52         }
53         return (s+3)/4;
54 }
55 bool dfs(int deep)
56 {
57     int i,j,d=h();
58     if(d==0)return true;
59     if(d+deep>ans)return false;
60     for(i=0;i<4;i++)
61         for(j=0;j<2;j++)
62         {
63             rot[j](p[i]);
64             if(dfs(deep+1))return true;
65             rot[j^1](p[i]);
66         }
67     return false;
68 }
69 int main()
70 {
71     //freopen("input.txt","r",stdin);
72     int i,j,sum,cs=0;
73     set_point();
74     while(scanf("%1d",&lim))
75     {
76         cs++;
77         sum=0;
78         for(i=0;i<3;i++)
79             for(j=0;j<3;j++)
80             {
81                 scanf("%1d",&board[i][j]);
82                 sum+=board[i][j];
83             }
84             sum+=lim;
85             if(sum==0)break;
86             //show_state();
87             ans=0;
88            while(ans<=lim&&!dfs(0))
89                ans++;
90            if(ans>lim)
91                printf("%d. %d\n",cs,-1);
92            else
93                printf("%d. %d\n",cs,ans);
94     }
95     return 0;
96 }

 

HDU 3459 Rubik 2×2×2

二阶段魔方问题。  ida*

估价函数:

在原点的那个方块是不动的,所心左,下,后三个面的颜色是确定的。 h()函数

先统计 这三个面上各自不应该出现的颜色的数量,并累加起来得到s。然后返回(s+3)/4   因为第次旋转会改变这三个面上最多4块的面积。

我写的这个暴力代码,基本是不用循环的。 希望能找到一定的规律以减少代码量。

代码在此:

View Code
  1 #include<iostream>
  2 #include<stdio.h>
  3 using namespace std;
  4 char G[6][9];
  5 int ans;
  6 char opt[4]="XYZ";
  7 char sto[200];
  8 void(*p[3])();
  9 void x_turn()
 10 {
 11     char a,b;
 12     a=G[4][3];
 13     b=G[5][3];
 14     G[5][3]=G[3][3]; G[4][3]=G[2][3];
 15     G[3][3]=G[1][3]; G[2][3]=G[0][3];
 16     G[1][3]=G[2][6]; G[0][3]=G[3][6];
 17     G[2][6]=b;       G[3][6]=a;
 18     char t=G[2][4];
 19     G[2][4]=G[2][5]; G[2][5]=G[3][5];
 20     G[3][5]=G[3][4]; G[3][4]=t;
 21 }
 22 void y_turn()
 23 {
 24     char a=G[2][6],b=G[2][7];
 25     int i;
 26     for(i=7;i>1;i-=2)
 27     {
 28         G[2][i]=G[2][i-2];
 29         G[2][i-1]=G[2][i-3];
 30     }
 31     G[2][1]=b; G[2][0]=a;
 32     char t=G[0][2];
 33     G[0][2]=G[0][3]; G[0][3]=G[1][3];
 34     G[1][3]=G[1][2]; G[1][2]=t;
 35 }
 36 void z_turn()
 37 {
 38     char a=G[1][2],b=G[1][3];
 39     G[1][2]=G[2][4]; G[1][3]=G[3][4];
 40     G[2][4]=G[4][3]; G[3][4]=G[4][2];
 41     G[4][3]=G[3][1]; G[4][2]=G[2][1];
 42     G[3][1]=a;       G[2][1]=b;
 43     char t=G[2][2];
 44     G[2][2]=G[2][3]; G[2][3]=G[3][3];
 45     G[3][3]=G[3][2]; G[3][2]=t;
 46 }
 47 void set_point()
 48 {
 49     p[0]=x_turn;
 50     p[1]=y_turn;
 51     p[2]=z_turn;
 52 }
 53 int h()
 54 {
 55     int sum=0;
 56     char a;
 57     a=G[3][0];
 58     if(G[3][1]!=a)sum++; if(G[2][0]!=a)sum++; if(G[2][1]!=a)sum++;
 59     a=G[5][2];
 60     if(G[5][3]!=a)sum++; if(G[4][2]!=a)sum++; if(G[4][3]!=a)sum++;
 61     a=G[3][7];
 62     if(G[3][6]!=a)sum++; if(G[2][6]!=a)sum++; if(G[2][7]!=a)sum++;
 63     return (sum+3)/4;
 64 }
 65 bool dfs(int deep)
 66 {
 67     int i;    
 68     int hz=h();
 69     if(hz==0)return true;
 70     if(deep+h()>ans)return false;
 71     char tmp[6][9];
 72     memcpy(tmp,G,sizeof(G));
 73     for(i=0;i<3;i++)
 74     {
 75         p[i]();
 76         sto[deep]=i;
 77         if(dfs(deep+1)) 
 78             return true;
 79         memcpy(G,tmp,sizeof(tmp));
 80     }
 81     return false;
 82 }
 83 int main()
 84 {
 85     //freopen("input.txt","r",stdin);
 86     int i;
 87     bool flag;
 88     char ps[6][9];
 89     
 90     set_point();
 91     while(true)
 92     {
 93         flag=false;
 94         for(i=0;i<6;i++)
 95             cin>>G[i];
 96         if(G[2][2]=='.')
 97             break;
 98         memcpy(ps,G,sizeof(G));
 99         ans=0;
100         while(!dfs(0))ans++;
101         memcpy(G,ps,sizeof(G));
102         for(i=0;i<ans;i++)
103             putchar(opt[sto[i]]);
104         putchar('\n');
105     }
106     return 0;
107 }

 

ida*也就这些了。

ida* A*  dfs比较

        A*算法 框架:

        估价函数: 

        状态存储: 

           判重:   

        就是bfs了。

        记录路径

            A* 是要用优先队列了。STL

 

ida*:

              估价函数h();

       bool    dfs(deep)

                   {

                            int hz=h();

                            if(hz==0)return true;

                             if(hz+deep>ans)return false;

                           计算  下一个状态。。if(dfs(deep+1))return true;

                              恢复环境。

       }

int main()

{

        读入数据;

   ans=0;

       while(!dfs(0)) ans++;

    cout<<ans<<endl;

}

 

ida*与A*相比,不用记录那么多状态,也不用判重。 如果问题的状态很多那就不能A*了

ida* 重复搜索很多。

ida*与普通dfs相比:

   有效的控制了深度,避免在一个方向上过度搜索。

于是,在问题的状态很多,而且深度可控制时可以用ida*

 

 估价函数的设计:

 算曼哈顿距离,还很常用。然后就尽量挖题里的限制吧。   有时个看似不起眼的估价,作用很大的。

 

状态存储和判重:

   康托。 hash   set map

STL的效率不怎么样啊。

注意代码不要出现中文空格啊,上次一不小心……

 

转载于:https://www.cnblogs.com/wyg031113/archive/2012/10/07/2713724.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值