【NOIP2015】斗地主(dfs)

练练码力。
如果没有顺子,显然最小出牌次数可以贪心,优先出四带二,然后三带一或三带二,最后出对拍和单牌。
把大小王归到单排一类中,最后特判如果剩余的单排大于2,把这两张当成大小王一起出。
枚举所有出顺子的情况,用三个dfs,其中:

dfs(int now, int l, int tot, int times)
//now 当前到了第几小的牌
//l 当前顺子的长度
//tot 当前已经出了几次牌
//times 当前大小的顺子(三顺,二顺,单顺)重复搜索了几遍

关于为什么要用用times记录并重复搜索:
考虑这组牌

[egin{aligned} 3quad4quad5quad6quad6quad7quad7quad8quad9quad10 end{aligned} ]

显然答案为两次,分别是3到7,6到10,中间有重复的部分,所以需要重复搜索。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;
const int N = 30;
const int h[] = {14, 12, 13, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
int n, ans = 1e9;
int card[N];
bool flag = false;
void check(int tt) {
	int t[5]; memset(t, 0, sizeof(t));
	for(int i = 1; i <= 15; i++) {
		t[card[i]]++;
	}
	while(t[4]) {
		if(t[1] >= 2) {
			t[4]--; t[1] -= 2; tt++; continue;
		}	else if(t[2] >= 2) {
			t[4]--; t[2] -= 2; tt++; continue;
		} else if(t[2] >= 1) {
			t[4]--; t[2]--; tt++; continue;
		} else {
			t[4]--; tt++; continue;
		}
	}
	while(t[3]) {
		if(t[1] >= 1) {
			t[3]--; t[1]--; tt++; continue;
		} else if(t[2] >= 1) {
			t[3]--; t[2]--; tt++; continue;
		} else {
			t[3]--; tt++; continue;
		}
	}
	while(t[2]) tt++, t[2]--;
	if(flag && t[1] >= 2) {
		t[1] -= 2; tt++;
	}
	tt += t[1];
	ans = min(ans, tt);
	return ;
}
void dfs2(int now, int l, int tot, int times) {
	if(now == 13) {
		if(l >= 5) {
			if(times < 4) dfs2(1, 0, tot + 1, times + 1);
			if(times == 4) check(tot + 1);
		}
		else if(l == 0) {
			if(times < 4) dfs2(1, 0, tot, times + 1);
			if(times == 4) check(tot);
		}
		return ;
	}
	if(card[now] >= 1) {
		card[now] -= 1;
		dfs2(now + 1, l + 1, tot, times);
		card[now] += 1;
		if(l >= 5) dfs2(now + 1, 0, tot + 1, times);
	} else {
		if(l >= 5) dfs2(now + 1, 0, tot + 1, times);
	}
	if(l == 0) dfs2(now + 1, 0, tot, times);
}

void dfs1(int now, int l, int tot, int times) {//2
	if(now == 13) {
		if(l >= 3) {
			if(times < 4) dfs1(1, 0, tot + 1, times + 1);
			if(times == 4) dfs2(1, 0, tot + 1, 0);
		}
		else if(l == 0) {
			if(times < 4) dfs1(1, 0, tot, times + 1);
			if(times == 4) dfs2(1, 0, tot, 0);
		}
		return ;
	}
	if(card[now] >= 2) {
		card[now] -= 2;
		dfs1(now + 1, l + 1, tot, times);
		card[now] += 2;
		if(l >= 3) dfs1(now + 1, 0, tot + 1, times);
	} else {
		if(l >= 3) dfs1(now + 1, 0, tot + 1, times);
	}
	if(l == 0) dfs1(now + 1, 0, tot, times);
}

void dfs(int now, int l, int tot, int times) {//3
	if(now == 13) {
		if(l >= 2) {
			if(times < 4) dfs(1, 0, tot + 1, times + 1);
			if(times == 4) dfs1(1, 0, tot + 1, 0);
		}
		else if(l == 0) {
			if(times < 4) dfs(1, 0, tot, times + 1);
			if(times == 4) dfs1(1, 0, tot, 0);
		}
		return ;
	}
	if(card[now] >= 3) {
		card[now] -= 3; 
		dfs(now + 1, l + 1, tot, times);
		card[now] += 3;
		if(l >= 2) dfs(now + 1, 0, tot + 1, times);
	} else {
		if(l >= 2) dfs(now + 1, 0, tot + 1, times);
	}
	if(l == 0) dfs(now + 1, 0, tot, times);
}

int main() {
//	freopen("data.in", "r", stdin);
	int T; scanf("%d%d", &T, &n);
	while(T--) {
		memset(card, 0, sizeof(card));
		ans = n; flag = false;
		for(int i = 1, x, y; i <= n; i++) {
			scanf("%d%d", &x, &y);
			if(x == 0 && y == 1) card[14]++;
			else if(x == 0 && y == 2) card[15]++;
			else card[h[x]]++;
		}
		if(card[14] && card[15]) flag = true;
		dfs(1, 0, 0, 0);
		printf("%d
", ans);
	}
	return 0;
}
原文地址:https://www.cnblogs.com/mcggvc/p/14058839.html