1. 程式人生 > >【NOIP2015提高組】鬥地主

【NOIP2015提高組】鬥地主

題目背景

NOIP2015 提高組 Day1 T3

題目描述

牛牛最近迷上了一種叫鬥地主的撲克遊戲。鬥地主是一種使用黑桃、紅心、梅花、方片的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 來表示數碼 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

輸出

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

輸出

6

備註 【樣例1說明】 共有 1 組手牌,包含 8 張牌:方片7,方片8,黑桃9,方片10,黑桃J,黑桃5,方片A以及黑桃A。可以通過打單順子(方片7,方片8,黑桃9,方片10,黑桃J),單張牌(黑桃5)以及對子牌(黑桃A以及方片A)在3次內打光。 【資料範圍】 對於不同的測試點,我們約定手牌組數 T 與張數 n 的規模如下: 資料保證:所有的手牌都是隨機生成的。

解析:

  大模擬?不不不,普通搜尋就行了。   考慮沒有順子的情況,那麼就可以貪心的進行出牌,出牌優先順序為順子>四帶二>四帶一>三帶二>三帶一>對子>單牌。因為出一次優先順序大的組合一定有多個優先順序小的組合組成的,所以貪心一定是是對的。   但是有了順子後,就不能證明貪心是對的,就直接搜尋順子是哪些,然後更新答案,必要的剪枝是肯定要加的。

程式碼:

#include <bits/stdc++.h>
using namespace std;

const int card[5]={0,5,3,2};
const int Max=16;
int n,m,ans,x,y,t;
int a[Max],sum[Max];

inline int calc()
{
	int tot=0;
	memset(sum,0,sizeof(sum));
	for(int i=0;i<=14;i++) if(i^1) sum[a[i]]++;
	while(sum[4]&&sum[2]>=2) tot++,sum[4]--,sum[2]-=2;
	while(sum[4]&&sum[1]>=2) tot++,sum[4]--,sum[1]-=2;
	while(sum[3]&&sum[2]) tot++,sum[3]--,sum[2]--;
	while(sum[3]&&sum[1]) tot++,sum[3]--,sum[1]--;
	return tot+sum[1]+sum[2]+sum[3]+sum[4];
}
inline void dfs(int step)
{
	if(step>=ans) return;
	ans=min(ans,step+calc());
	for(int same=3;same;same--)
	  for(int i=3;i<=13;i++)
	  {
		int j=i;
		while(a[j]>=same&&j<=14) j++;j--;
		if(j-i+1<card[same]) continue;
		for(int k=i;k<=i+card[same]-2;k++) a[k]-=same;
		for(int k=i+card[same]-1;k<=j;k++) a[k]-=same,dfs(step+1);
		for(int k=i;k<=j;k++) a[k]+=same;
	  }
}

int main()
{
	scanf("%d%d",&t,&n);
	while(t--)
	{
	  memset(a,0,sizeof(a)),ans=n;
	  for(int i=1;i<=n;i++) scanf("%d%d",&x,&y),x=x==1?14:x	,a[x]++;
	  dfs(0),printf("%d\n",ans);
	}
	return 0;
}