【noip2015】【搜索】鬥地主

鬥地主

牛牛最近迷上了一種叫鬥地主的撲克遊戲。鬥地主是一種使用黑桃、紅心、梅花、 方片的 A 到 K 加上大小王的共 54 張牌來進行的撲克牌遊戲。在鬥地主中,牌的大小關
系根據牌的數碼錶示如下:
3<4<5<6<7<8<9<10<J<Q<K<A<2<< ,而花色並不對牌的大小產生影響。每一局遊戲中,一副手牌由 n 張牌組成。遊戲者每次可以根據規定的牌型進行出牌,首先打光自己的手牌一方取得遊戲的勝利。
現在,牛牛隻想知道,對於自己的若干組手牌,分別最少需要多少次出牌可以將它們打光。請你幫他解決這個問題。
需要注意的是,本題中游戲者每次可以出手的牌型與一般的鬥地主相似而略有不同。
具體規則如下:
這裏寫圖片描述

輸入格式

第一行包含用空格隔開的 2 個正整數 T, n ,表示手牌的組數以及每組手牌的張數。
接下來 T 組數據,每組數據 n 行,每行一個非負整數對 ai,biai,bi,表示一張牌,其中 aiai 表示牌的數碼,bibi 表示牌的花色,中間用空格隔開。特別的,我們用 1 來表示數碼 A,11 表示數碼 J,12 表示數碼 Q,13 表示數碼 K;黑桃、紅心、梅花、方片分別用 1-4 來表示;小王的表示方法爲 0 1,大王的表示方法爲 0 2。

輸出格式

共 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

限制

對於不同的測試點,我們約定手牌組數 T 與張數 n 的規模如下:
測試點編號 T n 測試點編號 T n
1 100 2 11 100 14
2 100 2 12 100 15
3 100 3 13 10 16
4 100 3 14 10 17
5 100 4 15 10 18
6 100 4 16 10 19
7 100 10 17 10 20
8 100 11 18 10 21
9 100 12 19 10 22
10 100 13 20 10 23
數據保證:所有的手牌都是隨機生成的。

提示

【輸入輸出樣例 1 說明】
共有 1 組手牌,包含 8 張牌:方片 7,方片 8,黑桃 9,方片 10,黑桃 J,黑桃 5,方片 A 以及黑桃 A。可以通過打單順子(方片 7,方片 8,黑桃 9,方片 10,黑桃 J),單張牌(黑桃 5)以及對子牌(黑桃 A 以及方片 A)在 3 次內打光。

來源

NOIP 2015 提高組 Day 1 第三題

noip2015,去年的題,鬥地主是看了一個大神的做法的,和網上有一種貪心的不一樣,但大體思路是一樣的
就是搜索的時候先當沒有順子出完,更新答案,然後再搜索順子,dfs
好像聽說bfs可以直接過,我也不知道

我這裏是先用一個dp求出所有沒有順子的情況f[i][j][k]l[l]表示i個4張,j個3張,k個對子。l張單牌

然後就直接dfs就好了,程序很易讀,就直接放程序了

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<set>
#include<queue>
#include<algorithm>
#include<vector>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<stack>
#define INF 2100000000
#define ll long long
#define clr(x)  memset(x,0,sizeof(x))

using namespace std;

int dp[6][9][14][26],f[15],a[5];
int t,n,ans;

void dfs(int x)
{
    if(x>=ans)return ;
    clr(a);
    for(int i=0;i<=13;i++)
        a[f[i]]++;
    ans=min(ans,dp[a[4]][a[3]][a[2]][a[1]]+x);
    int s=2,e=2;
    for(int i=2;i<=14;i++)
    {
        if(f[i]>=1&&i<=13)e=i;
        else 
        {
            if(e-s>=4)
            {
                for(int S=s;S<=e-4;S++)
                {
                    for(int j=S;j<=S+3;j++)f[j]--;
                    for(int E=S+4;E<=e;E++)
                    {
                        f[E]--;
                        dfs(x+1);
                    }
                    for(int j=S;j<=e;j++)f[j]++;
                }
            }
            s=i+1;
        }
    }
    s=2,e=2;
    for(int i=2;i<=14;i++)
    {
        if(f[i]>=2&&i<=13)e=i;
        else 
        {
            if(e-s>=2)
            {
                for(int S=s;S<=e-2;S++)
                {
                    for(int j=S;j<=S+1;j++)f[j]-=2;
                    for(int E=S+2;E<=e;E++)
                    {
                        f[E]-=2;
                        dfs(x+1);
                    }
                    for(int j=S;j<=e;j++)f[j]+=2;
                }
            }
            s=i+1;
        }
    }
    s=2,e=2;
    for(int i=2;i<=14;i++)
    {
        if(f[i]>=3&&i<=13)e=i;
        else 
        {
            if(e-s>=2)
            {
                for(int S=s;S<=e-1;S++)
                {
                    f[S]-=3;
                    for(int E=S+1;E<=e;E++)
                    {
                        f[E]-=3;
                        dfs(x+1);
                    }
                    for(int j=S;j<=e;j++)f[j]+=3;
                }
            }
            s=i+1;
        }
    }
}
int main()
{

    cin>>t>>n;
    for(int i=0;i<=5;i++)
        for(int j=0;j<=8;j++)
            for(int k=0;k<=13;k++)
                for(int l=0;l<=25;l++)
                {
                    int &F=dp[i][j][k][l]=i+j+k+l;
                    if(i>0&&l>1)dp[i][j][k][l]=min(dp[i][j][k][l],dp[i-1][j][k][l-2]+1);
//                  if(i>0&&k>0)dp[i][j][k][l]=min(dp[i][j][k][l],dp[i-1][j][k-1][l]+1);
                    if(i>0&&k>1)dp[i][j][k][l]=min(dp[i][j][k][l],dp[i-1][j][k-2][l]+1);
                    if(j>0&&l>0)dp[i][j][k][l]=min(dp[i][j][k][l],dp[i][j-1][k][l-1]+1);
                    if(j>0&&k>0)dp[i][j][k][l]=min(dp[i][j][k][l],dp[i][j-1][k-1][l]+1);
                    if(i>0)F=min(F,min(dp[i-1][j+1][k][l+1],dp[i-1][j][k+2][l]));
                    if(j>0)F=min(F,dp[i][j-1][k+1][l+1]);
                    if(k>0)F=min(F,dp[i][j][k-1][l+2]);
                }
    while(t--)
    {
        clr(f);
        ans=INF;
        for(int i=1;i<=n;i++)
        {
            int A,B;
            scanf("%d%d",&A,&B);
            if(A==1)A+=13;
            if(A!=0)A--;
            f[A]++;
        }
        int b=0;
        if(f[0]==2)
        {
            f[0]=0;
            b++;
        }
        dfs(0);
        cout<<ans+b<<'\n';
    }
}

大概就是這個樣子,如果有什麼問題,或錯誤,請在評論區提出,謝謝。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章