zoukankan      html  css  js  c++  java
  • UVA

    题目链接

    紫书例题。

    首先附上我第一次bfs+剪枝TLE的版本:

      1 #include<bits/stdc++.h>
      2 
      3 using namespace std;
      4 typedef long long ll;
      5 const int N=24+2,inf=0x3f3f3f3f;
      6 const int b[][10]= {
      7     {0,2,6,11,15,20,22},
      8     {1,3,8,12,17,21,23},
      9     {10,9,8,7,6,5,4},
     10     {19,18,17,16,15,14,13},
     11     {23,21,17,12,8,3,1},
     12     {22,20,15,11,6,2,0},
     13     {13,14,15,16,17,18,19},
     14     {4,5,6,7,8,9,10},
     15 };
     16 const int md[]= {6,7,8,11,12,15,16,17};
     17 void rot(int* c,int x) {
     18     const int* bb=b[x];
     19     for(int i=0; i<6; ++i)swap(c[bb[i]],c[bb[i+1]]);
     20 }
     21 void enc(int* c,ll& x) {
     22     x=0;
     23     for(int i=23; i>=0; --i)x=x*3+c[i];
     24 }
     25 void dec(int* c,ll x) {
     26     for(int i=0; i<24; ++i)c[i]=0;
     27     for(int i=0; i<24; ++i)c[i]=x%3,x/=3;
     28 }
     29 int ok(int* c) {
     30     for(int i=0; i<7; ++i)if(c[md[i]]!=c[md[i+1]])return false;
     31     return true;
     32 }
     33 map<ll,int> d;
     34 vector<ll> t;
     35 int c[N],cc[N],s[N],mi;
     36 ll ss;
     37 
     38 void bfs1() {
     39     mi=inf;
     40     d.clear();
     41     t.clear();
     42     queue<ll> q;
     43     q.push(ss),d[ss]=0;
     44     while(!q.empty()) {
     45         ll u=q.front();
     46         q.pop();
     47         dec(c,u);
     48         if(ok(c)) {
     49             mi=min(mi,d[u]);
     50             t.push_back(u);
     51         }
     52         if(d[u]>=mi)continue;
     53         for(int i=0; i<8; ++i) {
     54             memcpy(cc,c,sizeof c);
     55             rot(cc,i);
     56             ll v;
     57             enc(cc,v);
     58             if(!d.count(v)) {
     59                 d[v]=d[u]+1;
     60                 q.push(v);
     61             }
     62         }
     63     }
     64 }
     65 
     66 void bfs2() {
     67     d.clear();
     68     queue<ll> q;
     69     for(ll i:t)q.push(i),d[i]=0;
     70     while(!q.empty()) {
     71         ll u=q.front();
     72         q.pop();
     73         if(d[u]==mi)continue;
     74         dec(c,u);
     75         for(int i=0; i<8; ++i) {
     76             memcpy(cc,c,sizeof c);
     77             rot(cc,i);
     78             ll v;
     79             enc(cc,v);
     80             if(!d.count(v)) {
     81                 d[v]=d[u]+1;
     82                 q.push(v);
     83             }
     84         }
     85     }
     86 }
     87 
     88 void prans() {
     89     ll u;
     90     for(u=ss; d[u];) {
     91         dec(c,u);
     92         for(int i=0; i<8; ++i) {
     93             memcpy(cc,c,sizeof c);
     94             rot(cc,i);
     95             ll v;
     96             enc(cc,v);
     97             if(d.count(v)&&d[v]==d[u]-1) {
     98                 printf("%c",i+'A');
     99                 u=v;
    100             }
    101         }
    102     }
    103     dec(c,u);
    104     printf("
    %d
    ",c[md[0]]+1);
    105 }
    106 
    107 int input() {
    108     for(int i=0; i<24; ++i)if(scanf("%d",&s[i])!=1)return 0;
    109     return 1;
    110 }
    111 
    112 int main() {
    113     while(input()) {
    114         for(int i=0; i<24; ++i)s[i]--;
    115         enc(s,ss);
    116         bfs1();
    117         bfs2();
    118         prans();
    119     }
    120     return 0;
    121 }
    View Code

    这个版本TLE的原因是,如果直接bfs的话,总状态数为$C(24,8)*C(16,8)=9465511770$,显然太大了,即使加了剪枝状态数依然很大,妥妥地TLE。

    但如果预先假定一个数是正确答案,那么剩下的两个数就没有区别了,所以状态可以用0和1来表示,这样总状态数就缩小到了$C(24,8)=735471$,在可接受范围内了。把原状态分解成三个子状态跑一遍bfs即可得到正确结果。但是如果对每个输入都跑一遍bfs的话依然会TLE,而我们发现对于每组输入,所有的状态表示的含义都是一样的,因此可以预先对末状态跑一遍bfs,记录下所有状态到末状态的最短距离,这样每接受一组输入都可以直接通过bfs树得到路径。

    bfs的版本:(状态的保存用了哈希表,用stl中的map应该也可以)

      1 #include<bits/stdc++.h>
      2 
      3 using namespace std;
      4 typedef long long ll;
      5 const int N=24+2,inf=0x3f3f3f3f;
      6 const int b[][10]= {
      7     {0,2,6,11,15,20,22},
      8     {1,3,8,12,17,21,23},
      9     {10,9,8,7,6,5,4},
     10     {19,18,17,16,15,14,13},
     11     {23,21,17,12,8,3,1},
     12     {22,20,15,11,6,2,0},
     13     {13,14,15,16,17,18,19},
     14     {4,5,6,7,8,9,10},
     15 };
     16 int t[]= {0,0,0,0,0,0,1,1,1,0,0,1,1,0,0,1,1,1,0,0,0,0,0};
     17 void rot(int* c,int x) {
     18     const int* bb=b[x];
     19     for(int i=0; i<6; ++i)swap(c[bb[i]],c[bb[i+1]]);
     20 }
     21 void enc(int* c,int& x) {
     22     x=0;
     23     for(int i=23; i>=0; --i)x=x<<1|c[i];
     24 }
     25 void dec(int* c,int x) {
     26     for(int i=0; i<24; ++i)c[i]=0;
     27     for(int i=0; i<24; ++i)c[i]=x&1,x>>=1;
     28 }
     29 struct Hashmap {
     30     static const int N=1e6+10;
     31     static const int mod=1e6+3;
     32     int hd[mod],nxt[N],tot,key[N],val[N];
     33     int H(int x) {return (x+233)%mod;}
     34     void clear() {tot=0; memset(hd,-1,sizeof hd);}
     35     int count(int x) {
     36         for(int u=hd[H(x)]; ~u; u=nxt[u])if(key[u]==x)return 1;
     37         return 0;
     38     }
     39     int& operator[](int x) {
     40         int h=H(x);
     41         for(int u=hd[h]; ~u; u=nxt[u])if(key[u]==x)return val[u];
     42         nxt[tot]=hd[h],key[tot]=x,val[tot]=0,hd[h]=tot;
     43         return val[tot++];
     44     }
     45 } d;
     46 
     47 int c[N],cc[N],s[N],ss,tt,mi,ans;
     48 string str1,str2;
     49 
     50 void bfs() {
     51     d.clear();
     52     queue<int> q;
     53     q.push(tt),d[tt]=0;
     54     while(!q.empty()) {
     55         int u=q.front();
     56         q.pop();
     57         dec(c,u);
     58         for(int i=0; i<8; ++i) {
     59             memcpy(cc,c,sizeof c);
     60             rot(cc,i);
     61             int v;
     62             enc(cc,v);
     63             if(!d.count(v)) {
     64                 d[v]=d[u]+1;
     65                 q.push(v);
     66             }
     67         }
     68     }
     69 }
     70 
     71 int input() {
     72     for(int i=0; i<24; ++i)if(scanf("%d",&s[i])!=1)return 0;
     73     return 1;
     74 }
     75 
     76 int main() {
     77     enc(t,tt);
     78     bfs();
     79     while(input()) {
     80         mi=inf;
     81         for(int i=1; i<=3; ++i) {
     82             for(int j=0; j<24; ++j)c[j]=s[j]==i?1:0;
     83             int u;
     84             enc(c,u);
     85             mi=min(mi,d[u]);
     86         }
     87         str1="Z";
     88         for(int i=1; i<=3; ++i) {
     89             for(int j=0; j<24; ++j)c[j]=s[j]==i?1:0;
     90             int u;
     91             enc(c,u);
     92             if(d[u]==mi) {
     93                 str2.clear();
     94                 while(u!=tt) {
     95                     dec(c,u);
     96                     for(int j=0; j<8; ++j) {
     97                         memcpy(cc,c,sizeof c);
     98                         rot(cc,j);
     99                         int v;
    100                         enc(cc,v);
    101                         if(d.count(v)&&d[v]==d[u]-1) {
    102                             str2.push_back(j+'A');
    103                             u=v;
    104                             break;
    105                         }
    106                     }
    107                 }
    108                 if(str2<str1)str1=str2,ans=i;
    109             }
    110         }
    111         if(mi==0)printf("No moves needed
    ");
    112         else printf("%s
    ",str1.c_str());
    113         printf("%d
    ",ans);
    114     }
    115     return 0;
    116 }
    View Code

    另外一种方法是IDA*。看了看网上的题解,基本都是IDA*的做法。IDA*还是很有参考价值的。

    设g(n)为从初始状态到当前状态n所需步数,h(n)为当前状态n到目标状态至少所需步数,则g(n)+h(n)>maxdep时剪枝。显然h(n)可以用中心格点中1,2,3中的最大个数与8的差来表示,这样就不用保存状态,直接搜就行了。IDA*特别适用于这种bfs树的宽度较大而深度较小的搜索问题。(可以用bfs跑一遍试试,会发现在用01状态表示法的情况下,最坏情况下达到目标状态也仅需14步。)

     1 #include<bits/stdc++.h>
     2 
     3 using namespace std;
     4 typedef long long ll;
     5 const int N=24+2,inf=0x3f3f3f3f;
     6 const int b[][10]= {
     7     {0,2,6,11,15,20,22},
     8     {1,3,8,12,17,21,23},
     9     {10,9,8,7,6,5,4},
    10     {19,18,17,16,15,14,13},
    11     {23,21,17,12,8,3,1},
    12     {22,20,15,11,6,2,0},
    13     {13,14,15,16,17,18,19},
    14     {4,5,6,7,8,9,10},
    15 };
    16 const int md[]= {6,7,8,11,12,15,16,17};
    17 void rot(int* c,int x,int f) {
    18     const int* bb=b[x];
    19     if(f==1)for(int i=0; i<6; ++i)swap(c[bb[i]],c[bb[i+1]]);
    20     else for(int i=5; i>=0; --i)swap(c[bb[i]],c[bb[i+1]]);
    21 }
    22 int count(int* c) {
    23     int cnt[3]= {};
    24     for(int i=0; i<8; ++i)cnt[c[md[i]]-1]++;
    25     return max(cnt[0],max(cnt[1],cnt[2]));
    26 }
    27 int s[N],ans;
    28 char str[N];
    29 
    30 bool dfs(int dep,int mxd) {
    31     int cnt=count(s);
    32     if(cnt==8) {ans=s[md[0]]; str[dep]=''; return 1;}
    33     if(8-cnt>mxd-dep)return 0;
    34     for(int i=0; i<8; ++i) {
    35         rot(s,i,1);
    36         if(dfs(dep+1,mxd)) {str[dep]=i+'A'; return 1;}
    37         rot(s,i,-1);
    38     }
    39     return 0;
    40 }
    41 
    42 void IDA() {
    43     for(int mxd=0;; ++mxd)if(dfs(0,mxd))break;
    44     if(str[0])puts(str);
    45     else puts("No moves needed");
    46     printf("%d
    ",ans);
    47 }
    48 
    49 int input() {
    50     for(int i=0; i<24; ++i)if(scanf("%d",&s[i])!=1)return 0;
    51     return 1;
    52 }
    53 
    54 int main() {
    55     while(input())IDA();
    56     return 0;
    57 }
    View Code

    怎么样,代码是不是比bfs的版本简洁多了?而且速度出乎意料地比bfs还要快很多。

    感觉IDA*就像暴搜+剪枝,bfs就像dp,具体该用哪个还得靠自己斟酌斟酌~~

  • 相关阅读:
    SpringBoot yml配置数据库密码特殊字符报错问题
    SpringBoot打jar包后无法访问resource下的文件
    js使用form提交工具类
    SpringBoot使用@ServerEndpoint无法@Autowired依赖注入问题解决
    java基于dfa实现敏感词过滤
    SpringBoot快速集成WebSocket实现群聊
    java生成序号前补0最简单的方法
    Mysql两个时间差计算方法
    python+selenium+webdriver环境搭建相关文档
    Java递归处理Tree树结构
  • 原文地址:https://www.cnblogs.com/asdfsag/p/10357259.html
Copyright © 2011-2022 走看看