vijos p1980鬥地主/luogu p2540鬥地主增強版
https://vijos.org/p/1980
https://www.luogu.org/problemnew/show/2540
這兩題的數據比原版鬥地主數據要毒瘤多了......特別是vj的一百個點......
把我在vj上寫的題解發一下吧......
dp[i][j][k][l][m]表示不考慮順子的情況下,(數碼相同的牌有四張的有i種【emmm也就是不算王炸的純炸彈有x個】,以此類推,有三張的有j種,兩張的有k種,一張的有l種,特別的,王的數量為m個)的情況,最少能夠出完牌的次數。
王之所以分開考慮是因為王炸不能算對子,四帶兩對和三帶一對的情況對於王炸要分開考慮,與其特判不如直接新開一維記錄
先預處理出能夠用得到的dp數組的值,然後dfs枚舉順子
本來dp數組中沒有考慮拆牌的情況,只有十多行的狀態轉移,洛谷上面的原版鬥地主能夠a掉,但是洛谷的鬥地主加強版和vijos的鬥地主都不行
於是狠心把所有能夠考慮到的拆牌的情況都寫了進去,令人窒息的五十行if......
其實有的拆牌情況可以不用考慮的,只是我當時實在是不想思考了......
幸好一遍過,沒有怎麽調試,否則我會瘋的......
#include <stdio.h>
#include <algorithm>
#include <string.h>
#define MAX4 7
#define MAX3 9
#define MAX2 14
#define MAX1 25
#define MAX0 2
using namespace std;
int T,n;
int card[30];
int dp[8][10][15][26][3];
int finalans;
inline int read()
{
int k=0,f=1;char c=getchar();
while(c<‘0‘||c>‘9‘){if(c==‘-‘)f=-1;c=getchar();}
while(c>=‘0‘&&c<=‘9‘){k=k*10+c-‘0‘;c=getchar();}
return k*f;
}
inline void DpBuild()
{
for(int i=0;i<=MAX4;i++)
{
for(int j=0;j<=MAX3;j++)
{
for(int k=0;k<=MAX2;k++)
{
for(int l=0;l<=MAX1;l++)
{
for(int m=0;m<=MAX0;m++)
{
dp[i][j][k][l][m]=i+j+k+l+(m==0?0:1);
}
}
}
}
}
for(int i=0;i<=MAX4;i++)
{
int usingj=(MAX1-4*i)/3+1;
for(int j=0;j<=usingj;j++)
{
int usingk=(MAX1-4*i-3*j)/2+1;
for(int k=0;k<=usingk;k++)
{
int usingl=(MAX1-4*i-3*j-2*k)+1;
for(int l=0;l<=usingl;l++)
{
for(int m=0;m<=MAX0;m++)
{
if(m>1) dp[i][j][k][l][m]=min(dp[i][j][k][l][m-2]+1,dp[i][j][k][l][m]);
if(m>0) dp[i][j][k][l][m]=min(dp[i][j][k][l][m-1]+1,dp[i][j][k][l][m]);
if(i>0) dp[i][j][k][l][m]=min(dp[i-1][j][k][l][m]+1,dp[i][j][k][l][m]);
if(l>0) dp[i][j][k][l][m]=min(dp[i][j][k][l-1][m]+1,dp[i][j][k][l][m]);
if(k>0) dp[i][j][k][l][m]=min(dp[i][j][k-1][l+1][m]+1,dp[i][j][k][l][m]);
if(j>0) dp[i][j][k][l][m]=min(dp[i][j-1][k+1][l][m]+1,dp[i][j][k][l][m]);
if(i>0) dp[i][j][k][l][m]=min(dp[i-1][j+1][k][l][m]+1,dp[i][j][k][l][m]);
if(k>0) dp[i][j][k][l][m]=min(dp[i][j][k-1][l][m]+1,dp[i][j][k][l][m]);
if(j>0) dp[i][j][k][l][m]=min(dp[i][j-1][k][l+1][m]+1,dp[i][j][k][l][m]);
if(i>0) dp[i][j][k][l][m]=min(dp[i+1][j][k-1][l][m]+1,dp[i][j][k][l][m]);
if(j>0) dp[i][j][k][l][m]=min(dp[i][j-1][k][l][m]+1,dp[i][j][k][l][m]);
if(i>0) dp[i][j][k][l][m]=min(dp[i-1][j][k][l+1][m]+1,dp[i][j][k][l][m]);
if(j>0&&m>0) dp[i][j][k][l][m]=min(dp[i][j-1][k][l][m-1]+1,dp[i][j][k][l][m]);
if(j>0&&l>0) dp[i][j][k][l][m]=min(dp[i][j-1][k][l-1][m]+1,dp[i][j][k][l][m]);
if(j>0&&k>0) dp[i][j][k][l][m]=min(dp[i][j-1][k-1][l+1][m]+1,dp[i][j][k][l][m]);
if(j>1) dp[i][j][k][l][m]=min(dp[i][j-2][k+1][l][m]+1,dp[i][j][k][l][m]);
if(j>0&&i>0) dp[i][j][k][l][m]=min(dp[i-1][j-1+1][k][l][m]+1,dp[i][j][k][l][m]);
if(i>0&&l>0) dp[i][j][k][l][m]=min(dp[i-1][j][k][l-1+1][m]+1,dp[i][j][k][l][m]);
if(i>0&&k>0) dp[i][j][k][l][m]=min(dp[i-1][j][k-1][l+2][m]+1,dp[i][j][k][l][m]);
if(i>0&&j>0) dp[i][j][k][l][m]=min(dp[i-1][j-1][k+1][l+1][m]+1,dp[i][j][k][l][m]);
if(i>1) dp[i][j][k][l][m]=min(dp[i-2][j+1][k][l+1][m]+1,dp[i][j][k][l][m]);
if(i>0&&m>0) dp[i][j][k][l][m]=min(dp[i-1][j][k][l+1][m-1]+1,dp[i][j][k][l][m]);
if(j>0&&k>0) dp[i][j][k][l][m]=min(dp[i][j-1][k-1][l][m]+1,dp[i][j][k][l][m]);
if(j>1) dp[i][j][k][l][m]=min(dp[i][j-2][k][l+1][m]+1,dp[i][j][k][l][m]);
if(j>0&&i>0) dp[i][j][k][l][m]=min(dp[i-1][j-1][k+1][l][m]+1,dp[i][j][k][l][m]);
if(i>0&&k>0) dp[i][j][k][l][m]=min(dp[i-1][j][k-1][l+1][m]+1,dp[i][j][k][l][m]);
if(i>0&&j>0) dp[i][j][k][l][m]=min(dp[i-1][j-1][k][l+2][m]+1,dp[i][j][k][l][m]);
if(i>1) dp[i][j][k][l][m]=min(dp[i-2][j][k+1][l+1][m]+1,dp[i][j][k][l][m]);
if(i>0&&l>0&&k>0) dp[i][j][k][l][m]=min(dp[i-1][j][k-1][l-1+1][m]+1,dp[i][j][k][l][m]);
if(i>0&&l>0&&j>0) dp[i][j][k][l][m]=min(dp[i-1][j-1][k+1][l-1][m]+1,dp[i][j][k][l][m]);
if(i>1&&l>0) dp[i][j][k][l][m]=min(dp[i-2][j+1][k][l-1][m]+1,dp[i][j][k][l][m]);
if(i>0&&m>1) dp[i][j][k][l][m]=min(dp[i-1][j][k][l][m-2]+1,dp[i][j][k][l][m]);
if(i>0&&k>1) dp[i][j][k][l][m]=min(dp[i-1][j][k-2][l+2][m]+1,dp[i][j][k][l][m]);
if(i>0&&j>0&&k>0) dp[i][j][k][l][m]=min(dp[i-1][j-1][k-1+1][l+1][m]+1,dp[i][j][k][l][m]);
if(i>1&&k>0) dp[i][j][k][l][m]=min(dp[i-2][j+1][k-1][l+1][m]+1,dp[i][j][k][l][m]);
if(i>0&&j>1) dp[i][j][k][l][m]=min(dp[i-1][j-2][k+2][l][m]+1,dp[i][j][k][l][m]);
if(i>1&&j>0) dp[i][j][k][l][m]=min(dp[i-2][j-1+1][k+1][l][m]+1,dp[i][j][k][l][m]);
if(i>2) dp[i][j][k][l][m]=min(dp[i-3][j+2][k][l][m]+1,dp[i][j][k][l][m]);
if(i>0&&k>0&&m>0) dp[i][j][k][l][m]=min(dp[i-1][j][k-1][l+1][m-1]+1,dp[i][j][k][l][m]);
if(i>0&&j>0&&m>0) dp[i][j][k][l][m]=min(dp[i-1][j-1][k+1][l][m-1]+1,dp[i][j][k][l][m]);
if(i>1&&m>0) dp[i][j][k][l][m]=min(dp[i-2][j+1][k][l][m-1]+1,dp[i][j][k][l][m]);
if(i>0&&j>0&&k>0) dp[i][j][k][l][m]=min(dp[i-1][j-1][k-1][l+1][m]+1,dp[i][j][k][l][m]);
if(i>1&&k>0) dp[i][j][k][l][m]=min(dp[i-2][j][k-1+1][l][m]+1,dp[i][j][k][l][m]);
if(i>0&&j>1) dp[i][j][k][l][m]=min(dp[i-1][j-2][k][l+2][m]+1,dp[i][j][k][l][m]);
if(i>1&&j>0) dp[i][j][k][l][m]=min(dp[i-2][j-1][k+1][l+1][m]+1,dp[i][j][k][l][m]);
if(i>2) dp[i][j][k][l][m]=min(dp[i-3][j][k+2][l][m]+1,dp[i][j][k][l][m]);
if(i>0&&k>1) dp[i][j][k][l][m]=min(dp[i-1][j][k-2][l][m]+1,dp[i][j][k][l][m]);
if(i>0&&l>1) dp[i][j][k][l][m]=min(dp[i-1][j][k][l-2][m]+1,dp[i][j][k][l][m]);
if(i>0&&k>0) dp[i][j][k][l][m]=min(dp[i-1][j][k-1][l][m]+1,dp[i][j][k][l][m]);
if(i>1) dp[i][j][k][l][m]=min(dp[i-2][j][k][l][m]+1,dp[i][j][k][l][m]);
if(i>0&&l>0&&m>0) dp[i][j][k][l][m]=min(dp[i-1][j][k][l-1][m-1]+1,dp[i][j][k][l][m]);
//printf("dp[%d][%d][%d][%d][%d]=%d\n",i,j,k,l,m,dp[i][j][k][l][m]);
}
}
}
}
}
}
void Search(int now)
{
for(int i=3;i<=13;i++)
{
if(card[i]>=3&&card[i+1]>=3)
{
card[i]-=3;card[i+1]-=3;
Search(now+1);
int j=i+2;
while(j<=14&&card[j]>=3)
{
card[j]-=3;
Search(now+1);
j++;
}
for(int k=i;k<j;k++)
{
card[k]+=3;
}
}
}
for(int i=3;i<=12;i++)
{
if(card[i]>=2&&card[i+1]>=2&&card[i+2]>=2)
{
card[i]-=2;card[i+1]-=2;card[i+2]-=2;
Search(now+1);
int j=i+3;
while(j<=14&&card[j]>=2)
{
card[j]-=2;
Search(now+1);
j++;
}
for(int k=i;k<j;k++)
{
card[k]+=2;
}
}
}
for(int i=3;i<=10;i++)
{
if(card[i]>0&&card[i+1]>0&&card[i+2]>0&&card[i+3]>0&&card[i+4]>0)
{
card[i]--;card[i+1]--;card[i+2]--;card[i+3]--;card[i+4]--;
Search(now+1);
int j=i+5;
while(j<=14&&card[j]>0)
{
card[j]--;
Search(now+1);
j++;
}
for(int k=i;k<j;k++)
{
card[k]++;
}
}
}
int num4=0,num3=0,num2=0,num1=0,joker=0;
for(int i=3;i<=15;i++)
{
if(card[i]==4) num4++;
else if(card[i]==3) num3++;
else if(card[i]==2) num2++;
else if(card[i]==1) num1++;
}
joker=card[16];
finalans=min(finalans,dp[num4][num3][num2][num1][joker]+now);
//printf("%d %d %d %d %d %d %d\n",num4,num3,num2,num1,joker,dp[num4][num3][num2][num1][joker]+now,finalans);
}
int main()
{
//freopen("landlords.in","r",stdin);
//freopen("landlords.out","w",stdout);
int x,y;
T=read();n=read();
DpBuild();
while(T--)
{
finalans=n;
memset(card,0,sizeof(card));
for(int i=1;i<=n;i++)
{
x=read();y=read();
if(x>=3&&x<=13) card[x]++;
else if(x>=1&&x<=2) card[x+13]++;
else if(x==0) card[16]++;
}
int num4=0,num3=0,num2=0,num1=0,joker=0;
for(int i=3;i<=15;i++)
{
if(card[i]==4) num4++;
else if(card[i]==3) num3++;
else if(card[i]==2) num2++;
else if(card[i]==1) num1++;
}
joker=card[16];
finalans=min(finalans,dp[num4][num3][num2][num1][joker]);
Search(0);
printf("%d\n",finalans);
}
return 0;
}
vijos p1980鬥地主/luogu p2540鬥地主增強版