记录编号 |
207248 |
评测结果 |
AAAAAAAAAAAAAAAAAAAA |
题目名称 |
[NOIP 2015]斗地主 |
最终得分 |
100 |
用户昵称 |
Skyo |
是否通过 |
通过 |
代码语言 |
C++ |
运行时间 |
0.613 s |
提交时间 |
2015-11-12 09:09:17 |
内存使用 |
1.96 MiB |
显示代码纯文本
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=30;
const int inf=0x7fff;
int T,N;
int cnt[maxn],seq[maxn];
void init()
{
memset(cnt,0,sizeof(cnt));
memset(seq,0,sizeof(seq));
}
int search()
{
if(N==2) {
if(seq[0]==seq[1]) return 1;
else return 2;
}
else if(N==3) {
if(seq[0]==seq[1] && seq[1]==seq[2]) return 1;
else if(seq[0]==seq[1] || seq[1]==seq[2]) return 2;
else return 3;
}
else if(N==4) {
if(cnt[seq[0]]==4) return 1;
else if(cnt[seq[0]]==1 && cnt[seq[1]]==3) return 1;
else if(cnt[seq[0]]==3 && cnt[seq[3]]==1) return 1;
else if(cnt[seq[0]]==2 && cnt[seq[2]]==2) return 2;
else if(seq[0]==seq[1] || seq[1]==seq[2] || seq[2]==seq[3])
return 3;
else return 4;
}
else {
int ans=inf;
int s1,s2,s3,t1,t2,t3;//顺子的首和尾
s1=s2=s3=t1=t2=t3=3;
bool finish=true;//牌是否出完
//以下用14表示A,15表示2,16表示王
for(int i=3;i<=16;i++) {
if(cnt[i]) {
finish=false;
t1=i;
if(t1-s1>=4 && i<15) {
for(int j=s1;j<=t1-4;j++)
for(int k=j+4;k<=t1;k++) {
for(int l=j;l<=k;l++) cnt[l]--;//出牌
ans=min(ans,search()+1);
for(int l=j;l<=k;l++) cnt[l]++;//回退
}//枚举顺子
}
if(cnt[i]>=2) {
t2=i;
if(t2-s2>=2 && i<15) {
for(int j=s2;j<=t2-2;j++)
for(int k=j+2;k<=t2;k++) {
for(int l=j;l<=k;l++) cnt[l]-=2;
ans=min(ans,search()+1);
for(int l=j;l<=k;l++) cnt[l]+=2;
}
}
}
else s2=i+1;
if(cnt[i]>=3) {
t3=i;
if(t3-s3>=1 && i<15) {
for(int j=s3;j<=t3-1;j++)
for(int k=j+1;k<=t3;k++) {
for(int l=j;l<=k;l++) cnt[l]-=3;
ans=min(ans,search()+1);
for(int l=j;l<=k;l++) cnt[l]+=3;
}
}
cnt[i]-=3;
for(int j=3;j<=16;j++) {
if(cnt[j] && j!=i) {
cnt[j]--;
ans=min(ans,search()+1);
cnt[j]++;
}//三带一
if(cnt[j]>=2 && j<16) {
cnt[j]-=2;
ans=min(ans,search()+1);
cnt[j]+=2;//抱歉这里刚才有个手误(但愿考场上别写错吧)
}//三带二,带的两张牌不能是王(?)
}
cnt[i]+=3;
}
else s3=i+1;
if(cnt[i]==4) {
cnt[i]-=4;
for(int j=3;j<=16;j++)
if(cnt[j]>=2) {
cnt[j]-=2;
ans=min(ans,search()+1);
cnt[j]+=2;
}//四带两张单牌,带的单牌点数相等
for(int j=3;j<16;j++)
for(int k=j+1;k<=16;k++) {
if(cnt[j] && cnt[k]) {
cnt[j]--;
cnt[k]--;
ans=min(ans,search()+1);
cnt[j]++;
cnt[k]++;
}//四带二单
if(cnt[j]>=2 && cnt[k]>=2 && k<16) {
cnt[j]-=2;
cnt[k]-=2;
ans=min(ans,search()+1);
cnt[j]+=2;
cnt[k]+=2;
}//四带两对
}
cnt[i]+=4;
}
}
else s1=s2=s3=i+1;
}
if(!finish) {
int temp=0;
for(int i=3;i<=16;i++) if(cnt[i]) temp++;
ans=min(ans,temp);
}//按点数处理完剩下的牌
if(finish) return 0;//递归终止
else return ans;
}
return 233;
}
int main()
{
freopen("landlords.in", "r", stdin);
freopen("landlords.out", "w", stdout);
scanf("%d%d",&T,&N);
while(T--) {
init();
for(int i=0;i<N;i++) {
int v, t;scanf("%d %d",&v,&t);
if(v==0) v=16;
else if(v<3) v+=13;
cnt[v]++;
seq[i]=v;
}
sort(seq,seq+N);
printf("%d\n",search());
}
return 0;
}