[Advanced] (2017-05-24) 沙漏

该博客介绍了一种利用深度优先搜索(DFS)策略来判断两个不同计时长度的沙漏是否能组合计时K秒的问题。在不超过10次翻转的限制下,通过递归遍历所有可能的翻转情况,寻找是否存在可行解。博客给出了具体的DFS实现代码,并展示了针对一系列测试用例的输出结果。
摘要由CSDN通过智能技术生成
两个沙漏分别可以计时N和M,初始状态两个沙漏所有的沙子都在上方
在任意一个沙漏到时间时(即一个确定的时间点),可以翻转沙漏,可以翻一个或者两个,也可以不翻转
求能否用这两个沙漏计时K,可以输出1,否则输出0


限制:
1<=N,M,K<=1000
总翻转次数不大于10,如果两个沙漏同时翻转算一次


输入:
用例数T
N, M, K
思路:
这个题并不要求最少翻转几次,而是只需要知道有没有可行解
所以其实是一道DFS题目
input:
9


3 5 7

12 13 118

8 3 9

1 103 18

4 3 41

5 7 17

5 16 23

5 19 26

7 27 36
output:
#1 1
#2 0
#3 1
#4 1
#5 0
#6 1
#7 1
#8 1
#9 1
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int T, N, M, K, answer;

void dfs(int time, int a, int b, int steps){
	// 如果已经不可能或者已经找到可行解,则在这里剪枝
	if (time > K || steps >= 10 || answer == 1){
		return;
	}
	// 当前的time再加上当前的状态可以计时的a或者b,如果能正好达到K,则说明可行,直接answer赋1返回。注意这里这样写,决定上面的剪枝必须是 steps >= 10,不能只是>
	if (time + a == K || time + b == K){
		answer = 1;
		return;
	}

	//根据a和b的大小分两种情况考虑
	if (a <= b){
		// 当较小的沙漏a流完时的三种情况
		// 这里对较小的沙漏a为0的情况进行剪枝
		/* 注意这里这个剪枝,不能跟上面的if并在一起,因为在较小的a=0时,也需要考虑较大的沙漏b流完时的三种情况
		   参考如下几个case:
		   5 16 23
		   5 19 26
		   7 27 36
		   */
		if (a != 0){
			dfs(time + a, N, b - a, steps + 1);
			dfs(time + a, 0, M - b + a, steps + 1); // M - b 是在这步之前,第二个沙漏下面初始的沙子
			dfs(time + a, N, M - b + a, steps + 1);
		}

		// 当较大的沙漏b流完时的三种情况(翻的是满的,不翻的是0)
		// 不需要考虑两个沙漏都为0的情况,因为这种情况直接就over了
		dfs(time + b, N, 0, steps + 1);
		dfs(time + b, 0, M, steps + 1);
		dfs(time + b, N, M, steps + 1);
	}
	else{
		// 当较小的沙漏b流完时的三种情况
		if (b != 0){
			dfs(time + b, a - b, M, steps + 1);
			dfs(time + b, N - a + b, 0, steps + 1); // N - a 是在这步之前,第一个沙漏下面初始的沙子
			dfs(time + b, N - a + b, M, steps + 1);
		}

		// 当较大的沙漏a流完时的三种情况(翻的是满的,不翻的是0)
		dfs(time + a, N, 0, steps + 1);
		dfs(time + a, 0, M, steps + 1);
		dfs(time + a, N, M, steps + 1);
	}
}

int main(int argc, char** argv) {
	freopen("sample_input.txt", "r", stdin);
	setbuf(stdout, NULL);
	scanf("%d", &T);
	for (int test_case = 1; test_case <= T; ++test_case){
		scanf("%d %d %d", &N, &M, &K);
		answer = 0;
		// 初始状态
		dfs(0, N, M, 0);
		printf("#%d %d\n", test_case, answer);
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值