问一副排n张,n<=23最少打几次打完,数据组数T<=100。
面向数据编程。。
前30分:乱暴力?没有顺子,把单、对子、炸弹、三张、王炸、三带一判一次即可。
前70分:状压,先预处理哪些状态能一次出完,用这些状态来转移,2^n*n*T。实际得分可能比期望的高一些??
满分:如果不打顺子,最优策略是可以确定的,三和四的能带走一二的就带走。所以dfs打顺子,然后贪心出剩下的牌。可以把ans做全局变量,然后搜索时>ans就退出以剪枝。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
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\n",ans); 104 } 105 return 0; 106 }
错误!有诸多未考虑到的情况,比如,4张3,4张3,3张5,可以两次打完;4张3,3张4,3张5,2张6,也可以两次打完。。。
不过这样可以满足网上大部分的数据了。。