zoukankan      html  css  js  c++  java
  • HDU

    题目链接

    基本思路:最理想的方法是预处理处所有胡牌的状态的哈希值,然后对于每组输入,枚举每种新加入的牌,然后用哈希检验是否满足胡牌的条件。然而不幸的是,由于胡牌的状态数过多(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 }
  • 相关阅读:
    【持续更新】养成一些好的C++编程习惯,争做一个不让同事骂街的程序员
    Inno Setup界面美化
    QWebengineView页面不实时刷新的问题
    Qt封装窗口进dll须知
    Inno Setup打包工具
    【转载】排序方式整理(带演示GIF)
    MySQL遇见SELECT list is not in GROUP BY clause and contains nonaggre的问题
    JMeter测试TCP协议
    Win10微软拼音关闭Ctrl+Shift+B快捷键
    Hive 窗口函数使用(1)
  • 原文地址:https://www.cnblogs.com/asdfsag/p/11366200.html
Copyright © 2011-2022 走看看