贪心、脑洞-Moving Tables HDU - 1050

看上去是一道贪心题,实际上确实一道贪心题,甚至还可以是一道脑洞题

贪心

开始的想法

开始我以为这是一个活动安排问题(书上也确实是这么说的),为什么呢,因为我们希望时间最短,很自然的就希望每个十分钟都能搬尽可能多的桌子,而每次搬运桌子,一段走廊就会被占用,这相当于一个活动占用了一段的时间。在这种理解下,我便认为这是一个不断重复的活动安排问题,只要每次安排的任务都是尽可能多的,那最后时间就是尽可能少的。(活动安排问题的策略是每次完成不发生冲突的结束时间最早的活动)

错误的想法

最后代码告诉我我是错的,例如这组数据

1
5
1 4
2 6
7 8
5 10
9 11

为什么会错呢,感觉还是贪心目光短浅了,它能保证每次在当前条件下安排最多数量,但操作过程并不是无后效性的,也就是说先前的决定会影响后来的决定。如图所示(这里假定房号是经过处理的)。

正确的想法

正确的想法应该是优先安排起始房号小的,这样可以让每次安排的区间更加紧密。我还不会证明正确性(有dalao明白的话请告诉我QAQ)。我感觉可能是因为每个区间都得被安排到,所以尽量紧密的话可能可以提高整体的效率吧。如图所示

代码

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;

struct node {
	int l, r;
};
bool cmp(node a, node b) {//让起始房号小的在前面 
	if (a.l != b.l)	return a.l < b.l;
	else return a.r < b.r;	
}//使用小于号,则小的在前面 
int main(void) {
	int T;
	cin >> T;
	node room[205];
	bool vis[205];
	while (T--) {
		memset(room, 0, sizeof(room));
		memset(vis, 0, sizeof(vis));
		int n;
		cin >> n;
		room[n].l = 0;room[n].r = 0;
		
		for (int i = 0; i < n; i++) {
			int a, b;
			cin >> a >> b;
			if (a > b) swap(a, b);//统一方向
			room[i].l = a % 2 == 0 ? a - 1 : a;//统一化处理 
			room[i].r = b % 2 == 0 ? b : b + 1;
		}
		sort(room, room + n, cmp);
		int ans = 0, cnt = 0;
		while (1) {
			int i = 0;
			while (vis[i]) i++;
			vis[i] = 1;//用while跳过前面已安排的元素,选中一个初始元素,并标记 
			if (i == n) break;//当每个元素都被安排了,就退出 
			int now = room[i].r;
			while(i++ < n){//扫描一遍所有元素,每次花十分钟 
				if (room[i].l > now && !vis[i]) {//错误:忘记加 && !vis[i]
					vis[i] = 1;//错误:忘记标记已访问的元素 
					now = room[i].r;
				}
			}
			ans += 10;
		}
		cout << ans << endl;
	}
	return 0;
}

p.s. 错误的思路和正确的思路的代码的差别就体现在cmp函数上。

脑洞

每次搬运可以看作是一段区间,我们只要求出区间的最大重叠数量,就是少需要花的搬运次数。

但由于本题房间的安排的特殊性,我们要做一个统一化的处理。

代码

#include <stdio.h>
#include <string.h>

#define SIZE 405

int main(void) {
	int count[SIZE];
	int i, j, testNum, n, max, from, to;

	scanf("%d", &testNum);
	while (testNum--) {
		scanf("%d", &n);
		memset(count, 0, sizeof(count));
		for (i = 0; i < n; i++) {
			scanf("%d%d", &from, &to);
			if (from > to) {
				int temp = from;
				from = to;
				to = temp;
			}
			from = from % 2 == 0 ? from - 1 : from;
			to = to % 2 == 0 ? to : to + 1;
			for (j = from; j <= to; j++) {
				count[j]++;
			}
		}
		max = 0;
		for (i = 0; i < SIZE; i++) {
			if (count[i] > max) {
				max = count[i];
			}
		}
		printf("%d\n", max * 10);
	}
	return 0;
}
posted @ 2021-11-19 16:51  tsrigo  阅读(4)  评论(0编辑  收藏  举报