【NOIP2015】斗地主

牛牛最近迷上了一种叫斗地主的扑克游戏。斗地主是一种使用黑桃、红心、梅花、方片的A到K加上大小王的共54张牌来进行的扑克牌游戏。在斗地主中,牌的大小关系根据牌的数码表示如下:3<4<5<6<7<8<9<10<J<Q<K<A<2<小王<大王,而花色并不对牌的大小产生影响。每一局游戏中,一副手牌由n张牌组成。游戏者每次可以根据规定的牌型进行出牌,首先打光自己的手牌一方取得游戏的胜利。 
现在,牛牛只想知道,对于自己的若干组手牌,分别最少需要多少次出牌可以将它们打光。请你帮他解决这个问题。 
需要注意的是,本题中游戏者每次可以出手的牌型与一般的斗地主相似而略有不同。 
具体规则如下:

P

Input

第一行包含用空格隔开的2个正整数Tn,表示手牌的组数以及每组手牌的张数。 
接下来T组数据,每组数据n行,每行一个非负整数对aibi表示一张牌,其中ai示牌的数码,bi表示牌的花色,中间用空格隔开。 特别的,我们用1来表示数码A,11表示数码J,12表示数码Q,13表示数码K;黑桃、红心、梅花、方片分别用1-4来表示;小王的表示方法为01,大王的表示方法为02。

Output

共T行,每行一个整数,表示打光第i手牌的最少次数。

Sample Input

样例输入1: 
1 8 
7 4 
8 4 
9 1 
10 4 
11 1 
5 1 
1 4 
1 1

样例输入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

Sample Output

样例输出1: 
3

样例输出2: 
6

这个题目可以用贪心搜索解决,对于每次枚举,我们总是先枚举顺子,尽量把牌打的多,之后的最优性剪枝就可以发挥出较大的作用了,
不过,还是有点难实现,不会的话看看代码吧:
#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<stdlib.h>
#include<cstring>
using namespace std;
int num[100];
int n,t,ans;
int h[5];
int suan(){
    int sum=0;
    memset(h,0,sizeof(h));
    for(int i=0;i<=14;i++){
        if(i==1) continue;
        h[num[i]]++;
    }
    while(h[4]>0&&h[2]>1) h[4]--,h[2]-=2,sum++;
    while(h[4]>0&&h[1]>1) h[4]--,h[1]-=2,sum++;
    while(h[3]>0&&h[2]>0) h[3]--,h[2]--,sum++;
    while(h[3]>0&&h[1]>0) h[3]--,h[1]--,sum++;
    return sum+h[4]+h[3]+h[2]+h[1];
}
void dfs(int now){
    if(now>=ans) return;
    for(int star=3;star<=14;star++){
        if(num[star]>=3){
            int end=15;
            for(int j=star+1;j<=14;j++) if(num[j]<3) {end=j;break;}
            if(end-star<2) continue;
            for(int k=end-star;k>=2;k--){
                for(int i=star;i<star+k;i++) num[i]-=3;
                dfs(now+1);
                for(int i=star;i<star+k;i++) num[i]+=3;
            }
            }
        }
    for(int star=3;star<=14;star++){
        if(num[star]>=2){
            int end=15;
            for(int j=star+1;j<=14;j++) if(num[j]<2) {end=j;break;}
            if(end-star<3) continue;
            for(int k=end-star;k>=3;k--){
                for(int i=star;i<star+k;i++) num[i]-=2;
                dfs(now+1);
                for(int i=star;i<star+k;i++) num[i]+=2;
            }
            }
        }
    for(int star=3;star<=14;star++){
        if(num[star]>=1){
            int end=15;
            for(int j=star+1;j<=14;j++) if(num[j]<1) {end=j;break;}
            if(end-star<5) continue;
            for(int k=end-star;k>=5;k--){
                for(int i=star;i<star+k;i++) num[i]-=1;
                dfs(now+1);
                for(int i=star;i<star+k;i++) num[i]+=1;
            }
            }
        }
    int tot=suan();
    ans=min(ans,tot+now);
    return;
}
int main(){
    cin>>t>>n;
    for(int q=1;q<=t;q++){
        memset(num,0,sizeof(num));
        ans=1<<30;
        for(int i=1;i<=n;i++){
            char x[2],y[2];
            int len;
            cin>>x>>y;
            len=strlen(x);
            if(len==1){
                if(x[0]=='1') num[14]++;
                else num[x[0]-'0']++;
            }
            else{
                if(x[0]=='0') num[0]++;
                else num[10+x[1]-'0']++;
            }
        }
        dfs(0);
        printf("%d
",ans);
    }
}
原文地址:https://www.cnblogs.com/renjianshige/p/7128190.html