【ybtoj高效进阶 21187】斗地主题(模拟)(DP)

斗地主题

题目链接:ybtoj高效进阶 21187

题目大意

打斗地主,对面只剩一张大鬼,到你出牌。
你不会有小鬼,然后问你你是否可以把牌都出掉。

思路

我们发现有可能会输的只有单牌。

那我们就没有必要出三个,炸这种(耍帅)没用的招,而是出三带一,四带二。

那我们就可以这样看,如果一张牌只有一个,那就是 1 1 1 费,如果有两个就是 0 0 0 费,三个就是 − 1 -1 1 费,四个就是 − 2 -2 2 费。我们就是要费小于等于 0 0 0

但是还有一个东西叫做顺子。
那你发现,你一张牌顺子了就少了一费,两张三张四张都是会多一费。

那你就相当于要找若干个区间,每个区间长度至少为 5 5 5,且框起来的数有最小费用。

然后 DP 一下就有了,这时候重新看费用就可以了。

代码

#include<cstdio>
#include<cstring>
#include<iostream>

using namespace std;

int n, a[21], bef, f[21];
int num[21], g[21];
char s[5];

int get_card() {
    
    
	scanf("%s", s + 1);
	int m = strlen(s + 1);
	if (m == 1) {
    
    
		if (s[1] == 'A') return 13;
		if (s[1] == 'K') return 12;
		if (s[1] == 'Q') return 11;
		if (s[1] == 'J') return 10;
		return s[1] - '0' - 1;
	}
	else {
    
    
		return 9;
	}
}

int main() {
    
    
//	freopen("landlords.in", "r", stdin);
//	freopen("landlords.out", "w", stdout);
	
	scanf("%d", &n);
	for (int i = 1; i <= n; i++) {
    
    
		a[i] = get_card();
		num[a[i]]++;
	}
	
	for (int i = 1; i <= 13; i++) {
    
    
		if (num[i] == 1) bef++, g[i] = 1;
			else if (num[i] == 2) g[i] = -1;
				else if (num[i] == 3) bef--, g[i] = -1;
					else if (num[i] == 4) bef -= 2, g[i] = -1;
						else g[i] = -1e7;
	}
	if (bef <= 1) {
    
    
		printf("Yes");
		return 0;
	}
	
	for (int i = 1; i <= 13; i++) g[i] += g[i - 1];
	for (int i = 6; i <= 13; i++) {
    
    
		f[i] = f[i - 1];
			for (int j = 5; j < i; j++) {
    
    
			f[i] = max(f[i], f[i - j] + g[i] - g[i - j]);
		}
	}
	if (bef - f[13] <= 1) {
    
    
		printf("Yes");
	}
	else {
    
    
		printf("No");
	}
	
	return 0;
}

Guess you like

Origin blog.csdn.net/weixin_43346722/article/details/121425006