UVa Live Archive 2326 - Moving Tables

传送门UVa Live Archive 2326 - Moving Tables


题意:给出几个搬桌子的情况,求最小用时。

注意如果从4→7,3→8的路都不能用了。


还有一点不太清楚,我觉得排序和不排序都一样,不排序就WA了。。奇怪。以后再来慢慢探究。


不明白为什么选择这个贪心策略是对的,看到了某个大神的证明。引用一下,备忘,日后研究。

引用自PhoenixDead


有四种贪心策略:最短优先,最长优先,最早开始时间优先,最早结束时间优先。活动安排问题采用的是最早结束时间优先。此题要求所有活动都被安排,直观的想同时进行的活动相互之间的间隔最小最好。可以证明最早开始时间优先满足要求。


证明:令S = P1,P2,P3,P4,P5是满足最早开始时间优先的一轮安排。即P1是所有活动中最早开始的,P2是在P1结束之后才开始的所有活动中最早开始的,依次类推。


假设存在最优解A不包含上述S的安排。我们要证明存在一个等价的最优解A‘包含上述的S安排。


由于P1是所有活动中最早开始的,所以A中必存在以P1开始的一轮安排,令为T = P1, T2, T3, T4,...Tn。


同时在A中,令包含 P2的一轮安排为B = B1,B2,...,P2,Bk,Bk+1,.. Bm。


由与P2是与P1相容活动中最早开始的,所以可以交换T2, T3, T4,...Tn与P2,Bk,Bk+1,.. Bm。得到新的安排T‘ = P1,P2,Bk,Bk+1,.. Bm和B' = B1,B2,...,T2, T3, T4,...Tn。


继续寻找包含P3的安排,依次类推,可以得到包含S的一个最优解A'。所以,任何最优解都可以转换为使用最早开始时间优先构造的解。证毕。



#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
const int MAXN = 200 + 10;

struct DESK
{
	int start, target;
	friend bool operator < (const DESK &a, const DESK &b)
	{
		return a.start < b.start;
	}
}desk[MAXN];

int vis[MAXN];
vector<int> curUsing;

int main()
{
	//freopen("input.txt", "r", stdin);
	//freopen("Correct.txt", "w", stdout);
	int T, i, j, n, cnt, ans, a, b;
	scanf("%d", &T);
	while (T--)
	{
		memset(vis, 0, sizeof(vis));
		cnt = ans = 0;
		scanf("%d", &n);
		for (i = 0; i < n; i++)
		{
			scanf("%d%d", &a, &b);
			desk[i].start = min(a, b);
			desk[i].target = max(a, b);
		}
		sort(desk, desk + n);
		while (cnt < n)
		{
			ans += 10;
			for (i = 0; i < n; i++)
			{
				if (!vis[i])
				{
					for (j = 0; j < curUsing.size(); j += 2)
					{
						int s = desk[i].start, t = desk[i].target;
						if (s >= curUsing[j] && s <= curUsing[j + 1] || t >= curUsing[j] && t <= curUsing[j + 1])
							break;
					}
					if (j >= curUsing.size())
					{
						cnt++;
						if (!(desk[i].start % 2))
							curUsing.push_back(desk[i].start - 1);
						else
							curUsing.push_back(desk[i].start);
						if (desk[i].target % 2)
							curUsing.push_back(desk[i].target + 1);
						else
							curUsing.push_back(desk[i].target);
						vis[i] = 1;
					}
				}
			}
			curUsing.clear();
		}
		printf("%d\n", ans);
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值