1. 程式人生 > >【NOIP 2015】鬥地主

【NOIP 2015】鬥地主

noi char 生活經驗 中間 也說 其他 一次 輸入 UNC

題目描述

牛牛最近迷上了一種叫鬥地主的撲克遊戲。鬥地主是一種使用黑桃、紅心、梅花、方片的 A 到 K 加上大小王的共 54 張牌來進行的撲克牌遊戲。在鬥地主中,牌的大小關 系根據牌的數碼表示如下: 3<4<5<6<7<8<9<10<J<Q<K<A<2<小王<大王,而花色並不對牌的大小產生影響。每一局遊戲中,一副手牌由 n 張牌組成。遊戲者每次可以根據規定的牌型進行出牌,首先打光自己的手牌一方取得遊戲的勝利。

現在,牛牛只想知道,對於自己的若幹組手牌,分別最少需要多少次出牌可以將它們打光。請你幫他解決這個問題。

需要註意的是,本題中遊戲者每次可以出手的牌型與一般的鬥地主相似而略有不同。具體規則如下:

技術分享圖片

輸入輸出格式

輸入格式:

第一行包含用空格隔開的2個正整數 T,n ,表示手牌的組數以及每組手牌的張數。

接下來 T 組數據,每組數據 n 行,每行一個非負數對 ai?,bi? ,表示一張牌,其中 ai? 表示牌的數碼,bi? 表示牌的花色,中間用空格隔開。特別的,我們用 1 來表示數碼 A11 表示數碼 J12 表示數碼 Q , 13 表示數碼 K ;黑桃、紅心、梅花、方片分別用 14 來表示;小王的表示方法為 01 ,大王的表示方法為 02 。

輸出格式:

T 行,每行一個整數,表示打光第 i 組手牌的最少次數。

輸入輸出樣例

輸入樣例#1:
1 8
7 4
8 4
9 1
10 4
11 1
5 1
1 4
1 1

輸出樣例#1:
3

輸入樣例#2:
1 17
12 3
4 3
2 3
5 4
10 2
3 3
12 2
0 1
1 3
10 1
6 2
12 1
11 3
5 2
12 4
2 2
7 2

輸出樣例#2:
6

題解

爆搜+大模擬:
有人會問:如何爆搜?
並不是真的純爆搜,只是爆搜順子,其余的牌貪心去打,註意順序(代碼裏有解釋);
此題也有一些坑,比如說‘2’不能放在順子裏(我被坑了很久,很少鬥地主)
,這也說明學OI也是需要一些生活經驗的;

code:
  1 #include<iostream>
  2 #include<cstdio>
  3 #include<algorithm>
  4 #include<cstring>
  5 #include<cctype>
  6 #define ll long long
  7 using namespace std;
  8 
  9 int read(){
 10     int X=0,w=0; char ch=0;
 11     while(!isdigit(ch)) {w|=ch==-;ch=getchar();}
 12     while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
 13     return w?-X:X;
 14 }
 15 int t,n,ans,ord,x,sum;
 16 int cnt[200],a[100];
 17 //下面函數都是return 以第i張牌為首能打出順的最大長度 
 18 int danshunzi(int i){
 19     int p=i;
 20     while(cnt[p]>=1&&p<=13)p++;
 21     if(p-i>=5)return p;
 22     return 0;
 23 }
 24 int shuangshunzi(int i){
 25     int p=i;
 26     while(cnt[p]>=2&&p<=13)p++;
 27     if(p-i>=3)return p;
 28     return 0;
 29 }
 30 int sanshunzi(int i){
 31     int p=i;
 32     while(cnt[p]>=3&&p<=13)p++;
 33     if(p-i>=2)return p;
 34     return 0;
 35 }
 36 //打完順子以後貪心打其他牌的最小次數
 37 //第2個while和第3個while順序不能換(雖然打出牌的數量一樣) 
 38 //因為要是單獨打單的話需要用兩次,而打對需要用一次;
 39 //所以貪心帶單 
 40 int    calc(){             
 41     int tot=0;   
 42     memset(a,0,sizeof(a));
 43     for(int i=0;i<=13;i++)a[cnt[i]]++;//桶套桶 ^-^ 
 44     while(a[4] && a[2]>1) a[4]--,a[2]-=2,tot++;// 8
 45     while(a[4] && a[1]>1) a[4]--,a[1]-=2,tot++;// 6  
 46     while(a[4] && a[2])   a[4]--,a[2]--,tot++;//  6
 47     while(a[3] && a[2])   a[3]--,a[2]--,tot++;//  5
 48     while(a[3] && a[1])   a[3]--,a[1]--,tot++;//  5
 49     return tot+a[1]+a[2]+a[3]+a[4];
 50 }
 51 
 52 void dfs(int dep){
 53     if(dep>=ans) return;
 54     int k=calc();
 55     ans=min(ans,dep+k);
 56     int pos;
 57     for(int i=2;i<=13;i++){
 58         if(sanshunzi(i)){                     //三順子 6+
 59             pos=sanshunzi(i);
 60             for(int v=i+1;v<=pos-1;v++){      //枚舉長度
 61                 for(int j=i;j<=v;j++) cnt[j]-=3;
 62                 dfs(dep+1);
 63                 for(int j=i;j<=v;j++) cnt[j]+=3;                
 64             }
 65         }        
 66     }
 67     for(int i=2;i<=13;i++){
 68         if(shuangshunzi(i)){                  //雙順子 6+
 69             pos=shuangshunzi(i);
 70             for(int v=i+2;v<=pos-1;v++){
 71                 for(int j=i;j<=v;j++) cnt[j]-=2;
 72                 dfs(dep+1);
 73                 for(int j=i;j<=v;j++) cnt[j]+=2;                
 74             }
 75         }
 76     }
 77     for(int i=2;i<=13;i++){
 78         if(danshunzi(i)){                      //單順子 5+ 
 79             pos=danshunzi(i);
 80             for(int v=i+4;v<=pos-1;v++){
 81                 for(int j=i;j<=v;j++) cnt[j]--;
 82                 dfs(dep+1);
 83                 for(int j=i;j<=v;j++) cnt[j]++;                
 84             }
 85         }
 86     }
 87 }
 88 
 89 int main()
 90 {
 91     freopen("cards.in","r",stdin);
 92     freopen("cards.out","w",stdout);
 93     t=read();n=read();
 94     while(t--){
 95         ans=30;
 96         memset(cnt,0,sizeof(cnt));
 97         for(int i=1;i<=n;i++){
 98             x=read();ord=read();
 99             if(x==1)x=13;      // A 
100             else if(x) x--;    // 1對應2 2對應3 ....... 
101             cnt[x]++;          // 這樣存可以解決2不能在順子裏的坑 
102         }
103         dfs(0);
104         printf("%d\n",ans);
105     }
106     return 0;
107 }
我覺得我該鬥兩把地主了 ^-^



【NOIP 2015】鬥地主