P2668 [NOIP2015 提高组] 斗地主
本文同步发表于我的博客园
没看到有人对贪心进行分析,并且第一篇题解哪怕是修改后还是错的,所以就试着推了一下然后写了这篇题解。
暴力搜顺子,DP(贪心)出散牌就不说了。
首先
但实际上尴尬的情况只有
并且我们可以发现这两种最先出肯定没问题。因为拆
出完后剩下如果还剩
特判完这两种情况后就没有
对于没有
#include<bits/stdc++.h>
using namespace std;
#define Min(x,y)((x)<(y)?x:y)
#define For(i,x,y)for(i=x;i<=(y);i++)
int num[16],h[5],mn;
void chupai(int step);
void shunzi(int step)
{
int i,j,k;
// cerr<<"shunzi0\n";
For(i,3,10)
{
j=i;
while(num[j])j++;
j--;
while(j>i+3)
{
For(k,i,j)num[k]--;
chupai(step+1);
For(k,i,j)num[k]++;
j--;
}
}
// cerr<<"shunzi1\n";
}
void liandui(int step)
{
int i,j,k;
// cerr<<"liandui0\n";
For(i,3,12)
{
j=i;
while(num[j]>1)j++;
j--;
while(j>i+1)
{
For(k,i,j)num[k]-=2;
chupai(step+1);
For(k,i,j)num[k]+=2;
j--;
}
}
// cerr<<"liandui1\n";
}
void feiji(int step)
{
int i,j,k;
// cerr<<"feiji0\n";
For(i,3,13)
{
j=i;
while(num[j]>2)j++;
j--;
while(j>i)
{
For(k,i,j)num[k]-=3;
chupai(step+1);
For(k,i,j)num[k]+=3;
j--;
}
}
// cerr<<"feiji1\n";
}
int sanpai()
{
int i,ret=0;
// cerr<<"sanpai0\n";
h[1]=num[1];
For(i,2,4)h[i]=0;
For(i,2,14)h[num[i]]++;
while(h[4]&&h[1]>1)h[4]--,h[1]-=2,ret++;
//4+2(1)
while(h[4]&&h[2]>1)h[4]--,h[2]-=2,ret++;
//4+2(2)
while(h[4]&&h[3])
{
if(!(h[4]&1)&&h[3]==1||h[4]==1&&h[3]==1&&h[2]&&h[1])break;
h[3]--,h[2]++,h[1]++;
while(h[4]&&h[2]>1)h[4]--,h[2]-=2,ret++;
while(h[4]&&h[1]>1)h[4]--,h[1]-=2,ret++;
}
//3->2,1 with 4
if(h[4]&&!(h[4]&1)&&h[3]==1)
{
h[4]--,h[2]++,h[1]=h[3]=0,ret++;
if(h[2]>1)h[2]-=2,h[4]--,ret++;
}
if(h[4]==1&&h[3]==1&&h[2]&&h[1])return ret+2;
//special cases
while(h[3]&&h[1])h[3]--,h[1]--,ret++;
//3+1
while(h[3]&&h[2])h[3]--,h[2]--,ret++;
//3+2
while(h[3]>1)
{
h[3]--,h[2]++,h[1]++;
while(h[3]&&h[1])h[3]--,h[1]--,ret++;
while(h[3]&&h[2])h[4]--,h[2]--,ret++;
}
//3->2,1 with 3
if(h[4]&&h[1])
{
h[4]--,h[1]=2,h[3]++;
if(h[2])h[3]=0,h[2]--,ret++;
else h[3]=0,h[1]--,ret++;
if(h[4])h[4]--,h[1]=0,ret++;
}
//4->3,1
if(h[4]&&h[2])h[4]--,h[2]=0,ret++;
//2->1,1 with 4
while(h[4]>1)h[4]-=2,ret++;
//4->2,2 with 4
// cerr<<"sanpai1\n";
return ret+h[1]+h[2]+h[3]+h[4]-(num[1]==2&&h[1]>1);
}
void chupai(int step)
{
if(step>=mn)return;
// cerr<<"chupai0\n";
int tmp=sanpai();
// cerr<<"chupai1\n";
mn=Min(mn,tmp+step);
shunzi(step);
liandui(step);
feiji(step);
}
int main()
{
int T,i,a,b,n;
cin>>T>>n;
while(T--)
{
mn=n;
For(i,1,14)num[i]=0;
For(i,1,n)cin>>a>>b,num[(!a?1:(a==1?14:a))]++;
chupai(0);
cout<<mn<<endl;
}
return 0;
}