[BZOJ 4325][NOIP 2015] 鬥地主
阿新 • • 發佈:2017-07-30
output ref input blank can 自己 show 我們 大模擬
一道防AK好題
4325: NOIP2015 鬥地主
Time Limit: 30 Sec Memory Limit: 1024 MB
Submit: 820 Solved: 560
[Submit][Status][Discuss]Description
牛牛最近迷上了一種叫鬥地主的撲克遊戲。鬥地主是一種使用黑桃、紅心、梅花、方片的A到K加上大小王的共54張牌來進行的撲克牌遊戲。在鬥地主中,牌的大小關系根據牌的數碼表示如下:3<4<5<6<7<8<9<10<J<Q<K<A<2<小王<大王,而花色並不對牌的大小產生影響。每一局遊戲中,一副手牌由n張牌組成。遊戲者每次可以根據規定的牌型進行出牌,首先打光自己的手牌一方取得遊戲的勝利。現在,牛牛只想知道,對於自己的若幹組手牌,分別最少需要多少次出牌可以將它們打光。請你幫他解決這個問題。需要註意的是,本題中遊戲者每次可以出手的牌型與一般的鬥地主相似而略有不同。具體規則如下:
Input
第一行包含用空格隔開的2個正整數T,N,表示手牌的組數以及每組手牌的張數。
接下來T組數據,每組數據N行,每行一個非負整數對Ai,Bi,表示一張牌,其中Ai表示牌的數碼,Bi表示牌的花色,中間用空格隔開。特別的,我們用1來表示數碼A,11表示數碼J,12表示數碼Q,13表示數碼K;黑桃、紅心、梅花、方片分別用1-4來表示;小王的表示方法為01,大王的表示方法為02。Output
共T行,每行一個整數,表示打光第T組手牌的最少次數。
Sample Input
1 8
7 4
8 4
9 1
10 4
11 15 1
1 4
1 1
Sample Output
3HINT
共有1組手牌,包含8張牌:方片7,方片8,黑桃9,方片10,黑桃J,黑桃5,方
片A以及黑桃A。可以通過打單順子(方片7,方片8,黑桃9,方片10,黑桃J),單張
牌(黑桃5)以及對子牌(黑桃A以及方片A)在3次內打光。
T<=10
N<=23
港真估計只有真正的$dalao$才能在考場上思路明確地碼完這題qwq
雖然實際寫出來代碼量倒也不算大,比某維修數列好到不知哪裏去了
這種大模擬的馬力出題人應該被掛起來裱(霧)
正解就是個大暴搜,$DFS$查找順牌的同時掃描查找帶牌...
查找帶牌時遵循盡量出最多的牌的貪心策略即可w
需要註意的是王牌可以出現在帶牌裏(四個 2 帶倆王2333333)但是王牌和2都不能出現在順子裏
其他的完全亂搞就行只要能保證正確性w
參考做法
GitHub
1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <iostream> 5 #include <algorithm> 6 7 int n; 8 int ans; 9 int sum[20]; 10 int cnt[10]; 11 12 int MakePair(); 13 void DFS(int); 14 void Initialize(); 15 int Convert(int); 16 17 int main(){ 18 int t; 19 scanf("%d%d",&t,&n); 20 while(t--){ 21 Initialize(); 22 ans=MakePair(); 23 DFS(0); 24 printf("%d\n",ans); 25 } 26 } 27 28 void Initialize(){ 29 int x,trash; 30 memset(sum,0,sizeof(sum)); 31 for(int i=0;i<n;i++){ 32 scanf("%d%d",&x,&trash); 33 sum[Convert(x)]++; 34 } 35 } 36 37 int MakePair(){ 38 memset(cnt,0,sizeof(cnt)); 39 int ans=0; 40 for(int i=1;i<=14;i++) 41 cnt[sum[i]]++; 42 while(cnt[4]>=1&&cnt[2]>=2){ 43 cnt[4]--; 44 cnt[2]-=2; 45 ans++; 46 } 47 while(cnt[4]>=1&&cnt[1]>=2){ 48 cnt[4]--; 49 cnt[1]-=2; 50 ans++; 51 } 52 while(cnt[3]>=1&&cnt[2]>=1){ 53 cnt[3]--; 54 cnt[2]--; 55 ans++; 56 } 57 while(cnt[3]>=1&&cnt[1]>=1){ 58 cnt[3]--; 59 cnt[1]--; 60 ans++; 61 } 62 ans+=cnt[1]+cnt[2]+cnt[3]+cnt[4]; 63 return ans; 64 } 65 66 void DFS(int deep){ 67 if(deep>ans) 68 return; 69 ans=std::min(ans,deep+MakePair()); 70 for(int i=1;i<=11;i++){ 71 int tmp=i; 72 while(tmp<=12&&sum[tmp]>=3) 73 tmp++; 74 tmp--; 75 if(tmp-i+1<2) 76 continue; 77 for(int k=tmp;k-i+1>=2;k--){ 78 for(int j=i;j<=k;j++) 79 sum[j]-=3; 80 DFS(deep+1); 81 for(int j=i;j<=k;j++) 82 sum[j]+=3; 83 } 84 } 85 for(int i=1;i<=10;i++){ 86 int tmp=i; 87 while(tmp<=12&&sum[tmp]>=2) 88 tmp++; 89 tmp--; 90 if(tmp-i+1<3) 91 continue; 92 for(int k=tmp;k-i+1>=3;k--){ 93 for(int j=i;j<=k;j++) 94 sum[j]-=2; 95 DFS(deep+1); 96 for(int j=i;j<=k;j++) 97 sum[j]+=2; 98 } 99 } 100 for(int i=1;i<=8;i++){ 101 int tmp=i; 102 while(tmp<=12&&sum[tmp]>=1) 103 tmp++; 104 tmp--; 105 if(tmp-i+1<5) 106 continue; 107 for(int k=tmp;k-i+1>=5;k--){ 108 for(int j=i;j<=k;j++) 109 sum[j]--; 110 DFS(deep+1); 111 for(int j=i;j<=k;j++) 112 sum[j]++; 113 } 114 } 115 } 116 117 inline int Convert(int x){ 118 if(x==0) 119 return 14; 120 else if(x==2) 121 return 13; 122 else if(x==1) 123 return 12; 124 else 125 return x-2; 126 }Backup
[BZOJ 4325][NOIP 2015] 鬥地主