鬥地主
牛牛最近迷上了一種叫鬥地主的撲克遊戲。鬥地主是一種使用黑桃、紅心、梅花、 方片的 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';
}
}
大概就是這個樣子,如果有什麼問題,或錯誤,請在評論區提出,謝謝。