4325: NOIP2015 斗地主
Time Limit: 30 Sec Memory Limit: 1024 MBSubmit: 638 Solved: 424
[ Submit][ Status][ Discuss]
Description
牛牛最近迷上了一种叫斗地主的扑克游戏。斗地主是一种使用黑桃、红心、梅花、方片的A到K加上大小王的共54张牌来进行的扑克牌游戏。在斗地主中,牌的大小关系根据牌的数码表示如下:3<4<5<6<7<8<9<10<J<Q<K<A<2<小王<大王,而花色并不对牌的大小产生影响。每一局游戏中,一副手牌由n张牌组成。游戏者每次可以根据规定的牌型进行出牌,首先打光自己的手牌一方取得游戏的胜利。现在,牛牛只想知道,对于自己的若干组手牌,分别最少需要多少次出牌可以将它们打光。请你帮他解决这个问题。需要注意的是,本题中游戏者每次可以出手的牌型与一般的斗地主相似而略有不同。具体规则如下:
Input
第一行包含用空格隔开的2个正整数T,N,表示手牌的组数以及每组手牌的张数。
接下来T组数据,每组数据N行,每行一个非负整数对Ai,Bi,表示一张牌,其中Ai表示牌的数码,Bi表示牌的花色,中间用空格隔开。特别的,我们用1来表示数码A,11表示数码J,12表示数码Q,13表示数码K;黑桃、红心、梅花、方片分别用1-4来表示;小王的表示方法为01,大王的表示方法为02。
Output
共T行,每行一个整数,表示打光第T组手牌的最少次数。
Sample Input
1 8
7 4
8 4
9 1
10 4
11 1
5 1
1 4
1 1
7 4
8 4
9 1
10 4
11 1
5 1
1 4
1 1
Sample Output
3
HINT
共有1组手牌,包含8张牌:方片7,方片8,黑桃9,方片10,黑桃J,黑桃5,方
片A以及黑桃A。可以通过打单顺子(方片7,方片8,黑桃9,方片10,黑桃J),单张
牌(黑桃5)以及对子牌(黑桃A以及方片A)在3次内打光。
T<=10
N<=23
Source
一定要读题,不要根据自己打牌的习惯想当然。。。。
就是每次搜索怎么出牌。要加一个最优化剪枝。如果当前还有k种牌,那么最多还会出k次。
还有就是单出的情况,不要搜索,直接用上面的最优化剪枝就可以得到这种答案。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#define N 100
using namespace std;
int n,m,num[N],ans;
int ke[10],step[N];
int pd()
{
for (int i=1;i<=15;i++)
if (num[i]) return 0;
return 1;
}
void dfs(int x)
{
if (x>ans) return;
int t=0;
for (int i=1;i<=13;i++)
if (num[i]) t++;
if (num[14]+num[15]) t++;
ans=min(ans,x-1+t);
if (pd()) {
ans=min(ans,x-1);
return;
}
int l=1; int r=1; int sum=0;
for (int i=1;i<=3;i++)
{
step[x]=i+4;
l=1; r=1;
while (l<=13) {
while (num[l]<i&&l<=13) l++,r++;
while (num[r]>=i&&r<=13) r++;
r--;
if (r<l) r=l;
if (r==13) r--;
int t=r-l+1;
if (t>=ke[i]) {
for (int t=l;t<=r-ke[i]+1;t++)
for (int j=l+ke[i]-1;j<=r;j++)
{
if (j-t+1<ke[i]) continue;
for (int k=t;k<=j;k++) num[k]-=i;
dfs(x+1);
for (int k=t;k<=j;k++) num[k]+=i;
}
}
l=r;
l++; r++;
if (l==13) break;
}
}
for (int i=1;i<=13;i++)
if (num[i]>=3) {
step[x]=2;
num[i]-=3;
for (int j=1;j<=15;j++)
{
if (num[j]>=1) {
num[j]--;
dfs(x+1);
num[j]++;
}
if (num[j]>=2) {
num[j]-=2;
dfs(x+1);
num[j]+=2;
}
}
num[i]+=3;
}
for (int i=1;i<=13;i++)
if (num[i]==4) {
step[x]=3;
num[i]-=4;
for (int t=1;t<=2;t++){
for (int j=1;j<=15;j++)
if (num[j]>=t) {
num[j]-=t;
for (int k=j;k<=15;k++)
if (num[k]>=t) {
num[k]-=t;
dfs(x+1);
num[k]+=t;
}
num[j]+=t;
}
}
num[i]+=4;
}
}
int main()
{
scanf("%d%d",&n,&m);
ke[1]=5; ke[2]=3; ke[3]=2;
for (int i=1;i<=n;i++) {
memset(num,0,sizeof(num));
int size=0;
for (int j=1;j<=m;j++) {
int x,y; scanf("%d%d",&x,&y);
if (x){
if (x>=3&&x<=13) num[x-2]++;
else num[x+11]++;
}
else num[y+13]++;
}
ans=0;
for (int i=0;i<=13;i++)
if (num[i]) ans++;
if (num[14]+num[15]) ans++;
dfs(1);
printf("%d\n",ans);
}
}