http://www.cnblogs.com/qingang/p/5724695.html 感觉这份代码简直是优美
首先让我们考虑没有顺子的情况,这个,分析还是分析的出来,不过如果你的欢乐斗地主能打够10000欢乐豆的话看一眼就知道怎么打了。贪心:
1.对于每一组牌来说,点的大小和花色是对答案没有影响的(毕竟只有你一个人自娱自乐),唯一有影响的就是每一张牌出现了多少次。
2.如果有3张或者4张出现的话,能多带几张走就劲量多带。
3.如果可以同时带走单牌或者双牌,先带走单牌,结果一定不会更差
再没有顺子的情况下,用以上几种贪心就可以讨论 所有情况了(叫你多做点博弈论自己不信)
但是在有顺子的情况下,每一张牌出现了多少次是会变化的,不满足贪心策略,别怕,n才多大,况且保证数据随机生成,不就是摆明叫你暴力搜吗?,每一次直接枚举出出顺子的情况,然后再利用上面的贪心策略就可以过了
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
int T,n,s[15],ans;
void dfs(int now){
int j,s1,s2,s3,s4;
s1=s2=s3=s4=0;
for(int i=1;i<=14;i++)if(s[i]==1)s1++;
for(int i=1;i<=14;i++)if(s[i]==2)s2++;
for(int i=1;i<=14;i++)if(s[i]==3){
s3++;
if(s1)s1--;
else if(s2)s2--;
}
for(int i=1;i<=14;i++)if(s[i]==4){
s4++;
if(s1>=2)s1-=2;
else if(s2>=2)s2-=2;
else if(s2)s2--;
}
ans=min(ans,now+s1+s2+s3+s4);
for(int i=1;i<=8;i++){
for(j=i;j<=12;j++){
if(!s[j])break;
s[j]--;
if(j-i+1>=5)dfs(now+1);
}
while(j>i)s[--j]++;
}
for(int i=1;i<=10;i++){
for(j=i;j<=12;j++){
if(s[j]<2)break;
s[j]-=2;
if(j-i+1>=3)dfs(now+1);
}
while(j>i)s[--j]+=2;
}
for(int i=1;i<=11;i++){
for(j=i;j<=12;j++){
if(s[j]<3)break;
s[j]-=3;
if(j-i+1>=2)dfs(now+1);
}
while(j>i)s[--j]+=3;
}
}
int main(){
scanf("%d%d",&T,&n);
while(T--){
memset(s,0,sizeof(s));
ans=1e9;
for(int x,b,i=1;i<=n;i++){
scanf("%d%d",&x,&b);
if(x==0)s[14]++;
else if(x==1)s[12]++;
else if(x==2)s[13]++;
else s[x-2]++;
}
dfs(0);
printf("%d\n",ans);
}
return 0;
}