这个麻将题还算挺友善的,比隔壁zjoi的要好得多。。。
比较正常的做法是五维dp
但事实上六维dp也是完全不会被卡的
七对子选权值最高的七个,国士无双直接$13^2$暴力
$dp[i][j][0/1][k][l][m]$表示枚举到了第i张牌,已经凑了j个面子,有无雀头,第i张牌已经用了k张,第i+1张牌用了l张,第i+2张牌用了m张,直接暴力转移。。。
然后你会得到50...
当然需要优化。
优化1:
枚举到dp值为0的直接continue,这样的不合法牌型有很多可以直接跳过。
优化2:
l和m只枚举到2,原因?如果枚举到三个顺子的话那么我们完全可以用三个刻子等效替代。
优化3:
不需要考虑杠。
原因?
$C_{4}^{3}=4$,$C_{4}^{4}=1$
就算这张牌是宝牌选刻子也必然优于杠子
代码就领略一下精神吧(
1 #include<cstdio> 2 #include<algorithm> 3 #include<queue> 4 #define d01(x) for(int x=0;x<2;x++) 5 using std::priority_queue; 6 using std::max; 7 typedef long long lint; 8 char si[3]; 9 void dm(lint &kk,lint l){kk=max(kk,l);} 10 11 int a[35],dora[35];//1~9,10~18,19~27,28,29,30,31,32,33,34 12 lint dp[36][5][2][5][3][3]; 13 lint dg[36]; 14 lint ans; 15 int c[5][5]={ 16 1,0,0,0,0, 17 1,1,0,0,0, 18 1,2,1,0,0, 19 1,3,3,1,0, 20 1,4,6,4,1 21 }; 22 int yaoku[15]={0,1,9,10,18,19,27,28,29,30,31,32,33,34}; 23 bool isyaoku[35]={0,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1}; 24 bool tail[35]={0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1}; 25 void kokushi() 26 { 27 int x; 28 for(int i=1;i<=13;i++) 29 { 30 x=yaoku[i]; 31 lint tmp=13; 32 tmp*=c[a[x]][2]*dora[x]*dora[x]; 33 for(int j=1;j<=13;j++) 34 { 35 if(i==j) continue;x=yaoku[j]; 36 tmp*=a[x]*dora[x]; 37 } 38 ans=max(ans,tmp); 39 } 40 } 41 priority_queue<int> q; 42 void chitoi() 43 { 44 lint tmp=7; 45 for(int i=1;i<=34;i++) q.push(c[a[i]][2]*dora[i]*dora[i]); 46 int g; 47 for(int i=1;i<=7;i++) 48 { 49 g=q.top(); 50 q.pop(); 51 tmp*=g; 52 } 53 ans=max(ans,tmp); 54 while(!q.empty()) q.pop(); 55 } 56 57 58 void clr() 59 { 60 for(int i=1;i<=35;i++) 61 { 62 dg[i]=0; 63 for(int j=0;j<=4;j++) 64 { 65 for(int k=0;k<=4;k++) 66 { 67 for(int l=0;l<=2;l++) 68 { 69 for(int m=0;m<=2;m++) 70 dp[i][j][0][k][l][m]=dp[i][j][1][k][l][m]=0; 71 } 72 } 73 } 74 } 75 for(int i=1;i<=34;i++) a[i]=4,dora[i]=1; 76 ans=0; 77 dp[1][0][0][0][0][0]=1; 78 } 79 int main() 80 { 81 int T; 82 scanf("%d",&T); 83 while(T--) 84 { 85 clr(); 86 while(1) 87 { 88 scanf("%s",si); 89 if(si[0]==‘0‘) break; 90 else if(si[1]==‘p‘) a[si[0]-‘0‘]--; 91 else if(si[1]==‘s‘) a[si[0]-‘0‘+9]--; 92 else if(si[1]==‘m‘) a[si[0]-‘0‘+18]--; 93 else if(si[0]==‘E‘) a[28]--; 94 else if(si[0]==‘S‘) a[29]--; 95 else if(si[0]==‘W‘) a[30]--; 96 else if(si[0]==‘N‘) a[31]--; 97 else if(si[0]==‘B‘) a[32]--; 98 else if(si[0]==‘F‘) a[33]--; 99 else if(si[0]==‘Z‘) a[34]--; 100 } 101 while(1) 102 { 103 scanf("%s",si); 104 if(si[0]==‘0‘) break; 105 else if(si[1]==‘p‘) dora[si[0]-‘0‘]=2; 106 else if(si[1]==‘s‘) dora[si[0]-‘0‘+9]=2; 107 else if(si[1]==‘m‘) dora[si[0]-‘0‘+18]=2; 108 else if(si[0]==‘E‘) dora[28]=2; 109 else if(si[0]==‘S‘) dora[29]=2; 110 else if(si[0]==‘W‘) dora[30]=2; 111 else if(si[0]==‘N‘) dora[31]=2; 112 else if(si[0]==‘B‘) dora[32]=2; 113 else if(si[0]==‘F‘) dora[33]=2; 114 else if(si[0]==‘Z‘) dora[34]=2; 115 } 116 kokushi();//国士无双 117 chitoi();//七对子 118 for(int i=1;i<=34;i++) 119 { 120 for(int j=0;j<=4;j++) 121 { 122 for(int k=0;k<=4;k++) 123 { 124 for(int l=0;l<=2;l++) 125 { 126 for(int m=0;m<=2;m++) 127 { 128 if(!dp[i][j][0][k][l][m]&&!dp[i][j][1][k][l][m]) continue; 129 if(a[i]-k>=2) dm(dp[i][j][1][k+2][l][m],dp[i][j][0][k][l][m]/c[a[i]][k]*c[a[i]][k+2]*dora[i]*dora[i]); 130 //雀头 131 if(j<4) 132 { 133 if(a[i]-k>=3) d01(o) dm(dp[i][j+1][o][k+3][l][m],dp[i][j][o][k][l][m]/c[a[i]][k]*c[a[i]][k+3]*dora[i]*dora[i]*dora[i]); 134 //刻子 135 if((!tail[i])&&a[i]-k>0&&a[i+1]-l>0&&a[i+2]-m>0&&l!=2&&m!=2) 136 d01(o) dm(dp[i][j+1][o][k+1][l+1][m+1],dp[i][j][o][k][l][m]/c[a[i]][k]*c[a[i]][k+1]*dora[i]/c[a[i+1]][l]*c[a[i+1]][l+1]*dora[i+1]/c[a[i+2]][m]*c[a[i+2]][m+1]*dora[i+2]); 137 //顺子 138 } 139 dm(dp[i+1][j][0][l][m][0],dp[i][j][0][k][l][m]); 140 dm(dp[i+1][j][1][l][m][0],dp[i][j][1][k][l][m]); 141 //转移 142 if(j==4) dg[i]=max(dg[i],dp[i][j][1][k][l][m]); 143 } 144 } 145 } 146 } 147 } 148 for(int i=1;i<=35;i++) ans=max(ans,dg[i]); 149 printf("%lld\n",ans); 150 } 151 return 0; 152 }
Orz
原文地址:https://www.cnblogs.com/rikurika/p/gxoi2019_1.html
时间: 2024-10-12 09:00:05