NOIP2015提高组D1T3 斗地主

问一副排n张,n<=23最少打几次打完,数据组数T<=100。

面向数据编程。。

前30分:乱暴力?没有顺子,把单、对子、炸弹、三张、王炸、三带一判一次即可。

前70分:状压,先预处理哪些状态能一次出完,用这些状态来转移,2^n*n*T。实际得分可能比期望的高一些??

满分:如果不打顺子,最优策略是可以确定的,三和四的能带走一二的就带走。所以dfs打顺子,然后贪心出剩下的牌。可以把ans做全局变量,然后搜索时>ans就退出以剪枝。

  1 #include<cstring>
  2 #include<cstdlib>
  3 #include<cstdio>
  4 //#include<assert.h>
  5 //#include<time.h>
  6 #include<math.h>
  7 //#include<queue>
  8 #include<algorithm>
  9 #include<iostream>
 10 using namespace std;
 11 
 12 bool isdigit(char c) {return c>='0' && c<='9';}
 13 int qread()
 14 {
 15     char c;int s=0,f=1;while (!isdigit(c=getchar())) f=(c=='-'?-1:1);
 16     do s=s*10+c-'0'; while (isdigit(c=getchar())); return s*f;
 17 }
 18 
 19 int T,n,ans;
 20 int a[25],cnt[25];
 21 int calc()
 22 {
 23     int ans=0;
 24     memset(cnt,0,sizeof(cnt));
 25     for (int i=1;i<=13;i++) cnt[a[i]]++;
 26     for (int i=1;i<=4;i++) cout<<cnt[i]<<' ';cout<<endl;
 27     bool wang=0;
 28     if (a[14] && a[15]) cnt[2]++,wang=1;
 29     else if (a[14] || a[15]) cnt[1]++;else{}
 30     
 31     while (cnt[4] && cnt[1]>1) ans++,cnt[4]--,cnt[1]-=2;
 32     while (cnt[4] && cnt[2]>1) ans++,cnt[4]--,cnt[2]-=2;
 33     while (cnt[3] && cnt[1]) ans++,cnt[3]--,cnt[1]--;
 34     while (cnt[3] && cnt[2])
 35     {
 36         if (cnt[2]==1 && wang) break;
 37         ans++,cnt[3]--,cnt[2]--;
 38     }
 39     ans+=cnt[1]+cnt[2]+cnt[3]+cnt[4];
 40     return ans;
 41 }
 42 void dfs(int dep)
 43 {
 44     if (dep>ans) return;
 45     int tmp=calc();
 46     if (dep+tmp<ans) ans=dep+tmp;
 47     //单顺子 
 48     for (int i=1;i<=8;i++)
 49     {
 50         int j=i;
 51         while (j<13 && a[j]) j++;
 52         for (int play=i+4;play<j;play++)
 53         {
 54             for (int k=i;k<=play;k++) a[k]--;
 55             dfs(dep+1);
 56             for (int k=i;k<=play;k++) a[k]++;
 57         }
 58     }
 59     //连对
 60     for (int i=1;i<=10;i++)
 61     {
 62         int j=i;
 63         while (j<13 && a[j]>1) j++;
 64         for (int play=i+2;play<j;play++)
 65         {
 66             for (int k=i;k<=play;k++) a[k]-=2;
 67             dfs(dep+1);
 68             for (int k=i;k<=play;k++) a[k]+=2;
 69         }
 70     }
 71     //三连对 
 72     for (int i=1;i<=11;i++)
 73     {
 74         int j=i;
 75         while (j<13 && a[j]>2) j++;
 76         for (int play=i+1;play<j;play++)
 77         {
 78             for (int k=i;k<=play;k++) a[k]-=3;
 79             dfs(dep+1);
 80             for (int k=i;k<=play;k++) a[k]+=3;
 81         }
 82     }
 83 }
 84 int main()
 85 {
 86     T=qread();
 87     n=qread();
 88     int x,y;
 89 while (T--)
 90 {
 91     memset(a,0,sizeof(a));
 92     for (int i=1;i<=n;i++)
 93     {
 94         x=qread();y=qread();
 95         if (x)
 96         {
 97             if (x>2) a[x-2]++;
 98             else a[x+11]++;
 99         }
100         else a[13+y]++;
101     }
102     ans=n;dfs(0);
103     printf("%d
",ans);
104 }
105     return 0;
106 }
View Code

错误!有诸多未考虑到的情况,比如,4张3,4张3,3张5,可以两次打完;4张3,3张4,3张5,2张6,也可以两次打完。。。

不过这样可以满足网上大部分的数据了。。

原文地址:https://www.cnblogs.com/Blue233333/p/7752922.html