UVA 1548 - The Game of Master-Mind(dfs剪枝)

链接:1548 - The Game of Master-Mind

题意:给定几个密码串的猜测情况,黑点代表位置和颜色完全匹配,白点代表颜色有出现过,位置不匹配,问密码的可能情况的最小字典序。
思路:dfs暴力,然后剪枝,剪枝为黑点超过个数或者总数超过总数就直接返回。
代码:
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;

const int N = 15;
const int M = 105;
int t, p, c, m, vis[M], have[M], hn, b[M], s[M], ans[N], num;
struct Mi {
	int num[N];
	int vis[M];
	int b, w;
} mi[M];

void init() {
	int i, j;
	memset(vis, 0, sizeof(vis));
	memset(b, 0, sizeof(b));
	memset(s, 0, sizeof(s));
	hn = 0;
	scanf("%d%d%d", &p, &c, &m);
	for (i = 0; i < m; i++) {
		memset(mi[i].vis, 0, sizeof(mi[i].vis));
		for (j = 0; j < p; j++) {
			scanf("%d", &mi[i].num[j]);
			mi[i].vis[mi[i].num[j]]++;
			if (!vis[mi[i].num[j]]) {
				vis[mi[i].num[j]] = 1;
				have[hn++] = mi[i].num[j];
			}
		}
		scanf("%d%d", &mi[i].b, &mi[i].w);
	}
	for (i = 1; i <= c; i++)
		if (!vis[i]) {
			have[hn++] = i;
			break;
		}
	sort(have, have + hn);
}

bool dfs(int d) {
	if (d == p) {
		for (int i = 0; i < m; i++) {
			if (b[i] != mi[i].b || s[i] - b[i] != mi[i].w)
				return false;
		}
		for (int j = 0; j < p - 1; j++)
			printf("%d ", ans[j]);
		printf("%d\n", ans[p - 1]);
		return true;
	}
	for (int i = 0; i < hn; i++) {
		int num = have[i], flag = 0, j, flag2[M];
		memset(flag2, 0, sizeof(flag2));
		for (j = 0; j < m; j++) {
			if (num == mi[j].num[d])
				b[j]++;
			if (mi[j].vis[num]) {
				s[j]++;
				mi[j].vis[num]--;
				flag2[j] = 1;
			}
			if (b[j] > mi[j].b || s[j] > mi[j].b + mi[j].w)
				flag = 1;
		}
		if (!flag) {
			ans[d] = num;
			if (dfs(d + 1)) return true;
		}
		for (j = 0; j < m; j++) {
			if (num == mi[j].num[d])
				b[j]--;
			if (flag2[j]) {
				s[j]--;
				mi[j].vis[num]++;
			}
		}
	}
	return false;
}

int main() {
	scanf("%d", &t);
	while (t--) {
		init();
		if (!dfs(0)) printf("You are cheating!\n");
	}
	return 0;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值