码迷,mamicode.com
首页 > 其他好文 > 详细

HDU - 4431 Mahjong (模拟+搜索+哈希+中途相遇)

时间:2019-08-16 22:40:13      阅读:104      评论:0      收藏:0      [点我收藏+]

标签:def   两种   输入   include   amp   pac   clu   选择   优化方法   

题目链接

基本思路:最理想的方法是预处理处所有胡牌的状态的哈希值,然后对于每组输入,枚举每种新加入的牌,然后用哈希检验是否满足胡牌的条件。然而不幸的是,由于胡牌的状态数过多(4个眼+一对将),预处理的复杂度太高($O(34^5)$),因此需要想办法优化一下。

我们可以预处理出所有“加上一对将之后可以胡牌”的状态,这样预处理的复杂度就成了$O(34^4)$,在可接受的范围内了。在检验的时候,只需要枚举去掉哪一对将,就可以$O(1)$检验是否能胡牌了(有种中途相遇的感觉),另外两种特殊情况单独判断即可。

玄学优化方法:

1.在dfs和枚举检验的时候动态维护哈希值,而不是每次重复计算,这样可以节省很大一部分计算哈希值的时间。

2.dfs的时候,每一层的初始下标都不小于上一层,这样可以避免很多重复状态。

3.用哈希表代替set,可以大幅缩短存取哈希值的时间。

4.预处理处所有不少于2张的牌,这样就不用每次枚举的时候都从头开始找了。

综上,总复杂度约为$O(34^4+20000*34*7)$,应该接近极限了吧。

其实这道题也没这么复杂,直接枚举将暴力吃碰就行了,但为了锻炼自己搜索的玄学优化能力还是选择了扬长避短o( ̄▽ ̄)d 

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef unsigned long long ll;
 4 const int N=13+5,inf=0x3f3f3f3f,M=19260817;
 5 const char* s="mspc";
 6 int id[300],a[4][N];
 7 ll p[4][N],pm[40],h;
 8 struct D {int x,y;};
 9 vector<D> vec,vv;
10 struct Hashset {
11     static const int N=4e5,M=1e6+3;
12     int hd[M],nxt[N],tot;
13     ll p[N];
14     void clear() {memset(hd,-1,sizeof hd),tot=0;}
15     void insert(ll x) {
16         int u=x%M;
17         for(int i=hd[u]; ~i; i=nxt[i])if(p[i]==x)return;
18         p[tot]=x,nxt[tot]=hd[u],hd[u]=tot++;
19     }
20     int count(ll x) {
21         int u=x%M;
22         for(int i=hd[u]; ~i; i=nxt[i])if(p[i]==x)return 1;
23         return 0;
24     }
25 } st;
26 void dfs(int dep,int x,int y) {
27     if(st.count(h))return;
28     if(dep==4) {st.insert(h); return;}
29     for(int i=x; i<=3; ++i)
30         for(int j=(i==x?y:1); j<=(i==3?7:9); ++j) {
31             if(a[i][j]<=1) {
32                 a[i][j]+=3,h+=3*p[i][j];
33                 dfs(dep+1,i,j);
34                 a[i][j]-=3,h-=3*p[i][j];
35             }
36             if(j<=7&&i!=3&&a[i][j]<=3&&a[i][j+1]<=3&&a[i][j+2]<=3) {
37                 a[i][j]++,a[i][j+1]++,a[i][j+2]++,h+=p[i][j]+p[i][j+1]+p[i][j+2];
38                 dfs(dep+1,i,j);
39                 a[i][j]--,a[i][j+1]--,a[i][j+2]--,h-=p[i][j]+p[i][j+1]+p[i][j+2];
40             }
41         }
42 }
43 bool Chii() {
44     for(int i=0; i<=3; ++i)
45         for(int j=1; j<=(i==3?7:9); ++j)if(a[i][j]&&a[i][j]!=2)return 0;
46     return 1;
47 }
48 bool Kokushi() {
49     for(int i=0; i<=3; ++i)
50         for(int j=1; j<=(i==3?7:9); ++j) {
51             if((i!=3&&(j==1||j==9))||(i==3)) {if(!a[i][j])return 0;}
52             else if(a[i][j])return 0;
53         }
54     return 1;
55 }
56 bool Hu() {
57     for(D t:vv)if(st.count(h-2*p[t.x][t.y]))return 1;
58     return 0;
59 }
60 bool ok() {return Chii()||Kokushi()||Hu();}
61 int main() {
62     st.clear();
63     id[m]=0,id[s]=1,id[p]=2,id[c]=3;
64     pm[0]=1;
65     for(int i=1; i<40; ++i)pm[i]=pm[i-1]*M;
66     for(int i=0,k=33; i<=3; ++i)
67         for(int j=1; j<=(i==3?7:9); ++j,--k)p[i][j]=pm[k];
68     dfs(0,0,1);
69     int T;
70     for(scanf("%d",&T); T--;) {
71         memset(a,0,sizeof a),h=0;
72         for(int i=0; i<13; ++i) {
73             int x;
74             char ch;
75             scanf("%d%c",&x,&ch);
76             a[id[ch]][x]++,h+=p[id[ch]][x];
77         }
78         vec.clear(),vv.clear();
79         for(int i=0; i<=3; ++i)
80             for(int j=1; j<=(i==3?7:9); ++j)if(a[i][j]>=2)vv.push_back({i,j});
81         for(int x=0; x<=3; ++x)
82             for(int y=1; y<=(x==3?7:9); ++y)if(a[x][y]<=3) {
83                     a[x][y]++,h+=p[x][y];
84                     if(a[x][y]==2)vv.push_back({x,y});
85                     if(ok())vec.push_back({x,y});
86                     if(a[x][y]==2)vv.pop_back();
87                     a[x][y]--,h-=p[x][y];
88                 }
89         if(vec.size()) {
90             printf("%d",vec.size());
91             for(D t:vec)printf(" %d%c",t.y,s[t.x]);
92             puts("");
93         } else puts("Nooten");
94     }
95     return 0;
96 }

还有一种极限优化的方法,因为不同花色的牌是可以独立考虑的,因此单独判断出每种花色的牌是否合法(全为3或者111),如果能胡的话,则必然有三种花色合法,一种花色不合法,其中不合法的一组必然有一对将,枚举这对将,然后判断剩下的牌是否合法即可。

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 typedef unsigned long long ll;
  4 const int N=13+2,inf=0x3f3f3f3f,M=19260817;
  5 const char* s="mspc";
  6 int id[300],a[4][N],c[N];
  7 ll pm[40],h[4],hh;
  8 struct D {int x,y;};
  9 vector<D> vec;
 10 struct Hashset {
 11     static const int N=4e5,M=1e6+3;
 12     int hd[M],nxt[N],tot;
 13     ll p[N];
 14     void clear() {memset(hd,-1,sizeof hd),tot=0;}
 15     void insert(ll x) {
 16         int u=x%M;
 17         for(int i=hd[u]; ~i; i=nxt[i])if(p[i]==x)return;
 18         p[tot]=x,nxt[tot]=hd[u],hd[u]=tot++;
 19     }
 20     int count(ll x) {
 21         int u=x%M;
 22         for(int i=hd[u]; ~i; i=nxt[i])if(p[i]==x)return 1;
 23         return 0;
 24     }
 25 } st1,st2;
 26 void dfs1(int dep,int u) {
 27     st1.insert(hh);
 28     if(dep==4)return;
 29     for(int i=u; i<=9; ++i) {
 30         if(c[i]<=1) {
 31             c[i]+=3,hh+=3*pm[i];
 32             dfs1(dep+1,i);
 33             c[i]-=3,hh-=3*pm[i];
 34         }
 35         if(c[i]<=3&&c[i+1]<=3&&c[i+2]<=3) {
 36             c[i]++,c[i+1]++,c[i+2]++,hh+=pm[i]+pm[i+1]+pm[i+2];
 37             dfs1(dep+1,i);
 38             c[i]--,c[i+1]--,c[i+2]--,hh-=pm[i]+pm[i+1]+pm[i+2];
 39         }
 40     }
 41 }
 42 void dfs2(int dep,int u) {
 43     st2.insert(hh);
 44     if(dep==4)return;
 45     for(int i=u; i<=7; ++i)if(c[i]<=1) {
 46             c[i]+=3,hh+=3*pm[i];
 47             dfs2(dep+1,i);
 48             c[i]-=3,hh-=3*pm[i];
 49         }
 50 }
 51 bool Chii() {
 52     for(int i=0; i<=3; ++i)
 53         for(int j=1; j<=(i==3?7:9); ++j)if(a[i][j]&&a[i][j]!=2)return 0;
 54     return 1;
 55 }
 56 bool Kokushi() {
 57     for(int i=0; i<=3; ++i)
 58         for(int j=1; j<=(i==3?7:9); ++j) {
 59             if((i!=3&&(j==1||j==9))||(i==3)) {if(!a[i][j])return 0;}
 60             else if(a[i][j])return 0;
 61         }
 62     return 1;
 63 }
 64 bool Hu() {
 65     int x=-1;
 66     for(int i=0; i<3; ++i)if(!st1.count(h[i])) {
 67             if(~x)return 0;
 68             x=i;
 69         }
 70     if(!st2.count(h[3])) {
 71         if(~x)return 0;
 72         x=3;
 73     }
 74     if(x!=3) {for(int i=1; i<=9; ++i)if(a[x][i]>=2&&st1.count(h[x]-2*pm[i]))return 1;}
 75     else {for(int i=1; i<=7; ++i)if(a[x][i]>=2&&st2.count(h[3]-2*pm[i]))return 1;}
 76     return 0;
 77 }
 78 bool ok() {return Chii()||Kokushi()||Hu();}
 79 int main() {
 80     st1.clear(),st2.clear();
 81     pm[0]=1;
 82     for(int i=1; i<40; ++i)pm[i]=pm[i-1]*M;
 83     id[m]=0,id[s]=1,id[p]=2,id[c]=3;
 84     dfs1(0,1),dfs2(0,1);
 85     int T;
 86     for(scanf("%d",&T); T--;) {
 87         memset(a,0,sizeof a);
 88         memset(h,0,sizeof h);
 89         for(int i=0; i<13; ++i) {
 90             int x;
 91             char ch;
 92             scanf("%d%c",&x,&ch);
 93             a[id[ch]][x]++,h[id[ch]]+=pm[x];
 94         }
 95         vec.clear();
 96         for(int x=0; x<=3; ++x)
 97             for(int y=1; y<=(x==3?7:9); ++y)if(a[x][y]<=3) {
 98                     a[x][y]++,h[x]+=pm[y];
 99                     if(ok())vec.push_back({x,y});
100                     a[x][y]--,h[x]-=pm[y];
101                 }
102         if(vec.size()) {
103             printf("%d",vec.size());
104             for(D t:vec)printf(" %d%c",t.y,s[t.x]);
105             puts("");
106         } else puts("Nooten");
107     }
108     return 0;
109 }

 

HDU - 4431 Mahjong (模拟+搜索+哈希+中途相遇)

标签:def   两种   输入   include   amp   pac   clu   选择   优化方法   

原文地址:https://www.cnblogs.com/asdfsag/p/11366200.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!