您的位置:首页 > 其它

【NOIP2015 DAY1 T3 】斗地主(landlords)

2016-08-06 10:54 441 查看

题目描述

牛牛最近迷上了一种叫斗地主的扑克游戏。斗地主是一种使用黑桃、红心、梅花、方片的A到K加上大小王的共54张牌来进行的扑克牌游戏。在斗地主中,牌的大小关系根据牌的数码表示如下:3<4<5<6<7<8<9<10<J<Q<K<A<2<小王<大王,而花色并不对牌的大小产生影响。每一局游戏中,一副手牌由n张牌组成。游戏者每次可以根据规定的牌型进行出牌,首先打光自己的手牌一方取得游戏的胜利。

现在,牛牛只想知道,对于自己的若干组手牌,分别最少需要多少次出牌可以将它们打光。请你帮他解决这个问题。

需要注意的是,本题中游戏者每次可以出手的牌型与一般的斗地主相似而略有不同。

具体规则如下:

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define Maxs 2000010

int n,maxx;
int sum[20],k[20],f[Maxs];

int mymin(int x,int y) {return x<y?x:y;}

void init()
{
int a,b;
for(int i=0;i<=13;i++) sum[i]=0;
for(int i=1;i<=n;i++)
{
scanf("%d%d",&a,&b);
sum[a]++;
}
k[0]=1;
for(int i=1;i<=13;i++) k[i]=k[i-1]*(sum[i-1]+1);
maxx=k[13]*(sum[13]+1)-1;
memset(f,63,sizeof(f));
f[0]=0;
}

int ffind(int s)
{
if(f[s]<100) return f[s];
int now[20];
int ss=s;
for(int i=13;i>=0;i--) if(sum[i])
{
if(i!=0)
{
now[i]=ss/k[i];
if(ss) ss%=k[i];
}
else now[i]=ss;
}
else now[i]=0;
//-dan-shunzi
for(int i=3;i<=9;i++)
{
bool ok=1;ss=s;
for(int j=i;j<=i+4;j++)
{
if(now[j]==0) {ok=0;break;}
ss-=k[j];
}
if(!ok) continue;
f[s]=mymin(f[s],ffind(ss)+1);
for(int j=i+5;j<=13;j++)
{
if(now[j]>=1)
{
ss-=k[j];
f[s]=mymin(f[s],ffind(ss)+1);
}
else {ok=0;break;}

}
if(now[1]&&ok)
{
ss-=k[1];
f[s]=mymin(f[s],ffind(ss)+1);
}
}
if(now[1]&&now[13]&&now[12]&&now[11]&&now[10])
f[s]=mymin(f[s],ffind(s-k[1]-k[13]-k[12]-k[11]-k[10])+1);
//shuang shun
for(int i=3;i<=11;i++)
{
bool ok=1;ss=s;
for(int j=i;j<=i+2;j++)
{
if(now[j]<2) {ok=0;break;}
ss-=k[j]*2;
}
if(!ok) continue;
f[s]=mymin(f[s],ffind(ss)+1);
for(int j=i+3;j<=13;j++)
{
if(now[j]>=2)
{
ss-=2*k[j];
f[s]=mymin(f[s],ffind(ss)+1);
}
else {ok=0;break;}

}
if(ok&&now[1]>=2)
{
ss-=2*k[1];
f[s]=mymin(f[s],ffind(ss)+1);
}
}
if(now[1]>=2&&now[13]>=2&&now[12]>=2)
f[s]=mymin(f[s],ffind(s-2*k[1]-2*k[13]-2*k[12])+1);
//san shun
for(int i=3;i<=12;i++)
{
if(now[i]<3||now[i+1]<3) continue;
ss=s-k[i]*3-k[i+1]*3;
f[s]=mymin(f[s],ffind(ss)+1);
bool ok=1;
for(int j=i+2;j<=13;j++)
{
if(now[j]>=3)
{
ss-=3*k[j];
f[s]=mymin(f[s],ffind(ss)+1);
}
else {ok=0;break;}

}
if(now[1]>=3&&ok)
{
ss-=3*k[1];
f[s]=mymin(f[s],ffind(ss)+1);
}
}
if(now[1]>=3&&now[13]>=3)
f[s]=mymin(f[s],ffind(s-3*k[1]-3*k[13])+1);
//4 dai 2
for(int i=1;i<=13;i++) if(now[i]==4)
{
ss=s-k[i]*4;
f[s]=mymin(f[s],ffind(ss)+1);
for(int j=0;j<=13;j++) if(i!=j&&now[j])
{
if(now[j]>=2) f[s]=mymin(f[s],ffind(ss-2*k[j])+1);
for(int l=j+1;l<=13;l++) if(l!=i&&now[l])
{
if(now[j]>=2&&now[l]>=2&&j!=0)
f[s]=mymin(f[s],ffind(ss-2*k[j]-2*k[l])+1);
f[s]=mymin(f[s],ffind(ss-k[j]-k[l])+1);
}
}
}
//san dai x
for(int i=1;i<=13;i++) if(now[i]>=3)
{
ss=s-k[i]*3;
f[s]=mymin(f[s],ffind(ss)+1);
for(int j=0;j<=13;j++) if(now[j]>=1&&i!=j) f[s]=mymin(f[s],ffind(ss-k[j])+1);
for(int j=1;j<=13;j++) if(now[j]>=2&&i!=j) f[s]=mymin(f[s],ffind(ss-2*k[j])+1);
}
for(int i=0;i<=13;i++) if(now[i]>=1) f[s]=mymin(f[s],ffind(s-k[i])+1);
for(int i=0;i<=13;i++) if(now[i]>=2) f[s]=mymin(f[s],ffind(s-2*k[i])+1);
return f[s];
}

int main()
{
int T;
scanf("%d%d",&T,&n);
while(T--)
{
init();
ffind(maxx);
printf("%d\n",f[maxx]);
}
return 0;
}


landlords

2016-08-06 10:57:25
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: