【BZOJ4325】NOIP2015 斗地主 搜索+贪心

这个东西考试的时候一眼以为状压就压炸了考试又了一下午.....最后我打出来发现后几个点10min都过不去,我大概算了一下,可能是吧.......最后一脸懵逼的我去怂了正解,我们发现只要确定了顺子就可以贪心了,所谓贪心就是在扔相同数码牌的基础上从四带二(对),四带二,三带二,三带一,开始贪心,我们的二,一一定是它本身就是这么大,因为,如果不是的话我们只是浪费了弹药却不能得到优惠,而且由于一个四可以带两个一样的单张,我们就不会出现三拆四捡的情况,我们可以把它们看成四类物品,一类是一个的,一类是两个的......,因此我们发现只有三,四物品才可以去带,而且四可以一下带俩,三可以一下一个,我们就变成了,用两种武器去打两种小怪打得最多为最优。

别忘了剪枝。

#include <cstdio>
#include <cstring>
#define N 25
#define r register
using namespace std;
int a[N],c[N],n,T,ans;
inline int read()
{
  r int sum=0;
  r char ch=getchar();
  while(ch<'0'||ch>'9')ch=getchar();
  while(ch>='0'&&ch<='9')
  {
    sum=(sum<<1)+(sum<<3)+ch-'0';
    ch=getchar();
  }
  return sum;
}
inline int Min(int x,int y)
{
  return x<y?x:y;
}
inline int Just()
{
  memset(c,0,sizeof(c));
  r int t=0;
  for(r int i=1;i<=14;i++)c[a[i]]++;
  while(c[4]&&c[2]>=2)c[4]--,c[2]-=2,t++;
  while(c[4]&&c[1]>=2)c[4]--,c[1]-=2,t++;
while(c[4]&&c[2])c[4]--,c[2]--,t++;
while(c[3]&&c[2])c[3]--,c[2]--,t++; while(c[3]&&c[1])c[3]--,c[1]--,t++; return c[1]+c[2]+c[3]+c[4]+t; } void dfs(int now) { if(now>=ans)return; ans=Min(ans,now+Just()); for(r int i=1;i<=11;i++) { r int k=i; while(k<=12&&a[k]>=3)k++; k--; if(k-i+1<2)continue; for(;k-i+1>=2;k--) { for(r int j=i;j<=k;j++)a[j]-=3; dfs(now+1); for(r int j=i;j<=k;j++)a[j]+=3; } } for(r int i=1;i<=10;i++) { r int k=i; while(k<=12&&a[k]>=2)k++; k--; for(;k-i+1>=3;k--) { for(r int j=i;j<=k;j++)a[j]-=2; dfs(now+1); for(r int j=i;j<=k;j++)a[j]+=2; } } for(r int i=1;i<=8;i++) { r int k=i; while(k<=12&&a[k])k++; k--; for(;k-i+1>=5;k--) { for(r int j=i;j<=k;j++)a[j]--; dfs(now+1); for(r int j=i;j<=k;j++)a[j]++; } } } int main() { T=read(),n=read(); while(T--) { memset(a,0,sizeof(a)); for(r int i=1,x;i<=n;i++) { scanf("%d%*d",&x); if(x==1)a[12]++; else if(x==2)a[13]++; else if(x)a[x-2]++; else a[14]++; } ans=Just(); dfs(0); printf("%d ",ans); } }
原文地址:https://www.cnblogs.com/TSHugh/p/7260503.html