【uoj147】NOIP2015—斗地主

http://uoj.ac/problem/147 (题目链接)

题意

  打牌。。。

Solution

  其实很简单的搜索,当年还是太年轻了。稍微想一想,顺子肯定是要先打掉的,因为顺子所包含的牌最多,所以我们可以以打出了多少张顺子为状态进行搜索,每一种状态,贪心去计算一下对于当前状态还需要打多少次才能将牌打完,不断更新答案即可。

代码

// uoj147
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<queue>
#define MOD 1000000007
#define inf 2147483640
#define LL long long
#define free(a) freopen(a".in","r",stdin);freopen(a".out","w",stdout);
using namespace std;

const int maxn=30;
int c[5],a[maxn],n,T,ans;

int cal() {
	memset(c,0,sizeof(c));
	for (int i=0;i<=13;i++) c[a[i]]++;
	int tot=0;
	while (c[4] && c[2]>1) c[4]--,c[2]-=2,tot++;
	while (c[4] && c[1]>1) c[4]--,c[1]-=2,tot++;
	while (c[4] && c[2]) c[4]--,c[2]--,tot++;
	while (c[3] && c[2]) c[3]--,c[2]--,tot++;
	while (c[3] && c[1]) c[3]--,c[1]--,tot++;
	return tot+c[1]+c[2]+c[3]+c[4];
}
void dfs(int x) {
	if (x>=ans) return;
	int tmp=cal();
	ans=min(ans,tmp+x);
	for (int i=2;i<=13;i++) {
		int j=i;
		while (a[j]>=3) j++;
		if (j-i>=2) {
			for (int k=i+1;k<=j-1;k++) {
				for (int l=i;l<=k;l++) a[l]-=3;
				dfs(x+1);
				for (int l=i;l<=k;l++) a[l]+=3;
			}
		}
	}
	for (int i=2;i<=13;i++) {
		int j=i;
		while (a[j]>=2) j++;
		if (j-i>=3) {
			for (int k=i+2;k<=j-1;k++) {
				for (int l=i;l<=k;l++) a[l]-=2;
				dfs(x+1);
				for (int l=i;l<=k;l++) a[l]+=2;
			}
		}
	}
	for (int i=2;i<=13;i++) {
		int j=i;
		while (a[j]>=1) j++;
		if (j-i>=5) {
			for (int k=i+4;k<=j-1;k++) {
				for (int l=i;l<=k;l++) a[l]--;
				dfs(x+1);
				for (int l=i;l<=k;l++) a[l]++;
			}
		}
	}
}
int main() {
	int T;scanf("%d%d",&T,&n);
	while (T--) {
		memset(a,0,sizeof(a));
		for (int x,y,i=1;i<=n;i++) {
			scanf("%d%d",&x,&y);
			if (x==1) x=13;
			else if (x) x--;
			a[x]++;
		}
		ans=n;
		dfs(0);
		printf("%d
",ans);
	}
	return 0;
}

  

原文地址:https://www.cnblogs.com/MashiroSky/p/5916311.html