题目链接:POJ 1083
题意:
有400间房间依次有序分布在一条走廊两侧,每10分钟可以将一张桌子从一间房间搬到另一间,但是在这十分钟搬桌子时需要占用从出发房间到目标房间的所有走廊,要想在同一个10分钟搬超过一张桌子那么所占用的走廊不能有交集。而且每间房间最多搬出或搬入一张桌子。
分析:
注意!房间门号的分布!1和2,3和4,4和5,...,之间都是同一条走廊,如果将这些走廊编号的话,将房间号记为i那么走廊编号就是(i+1)/2;由于在同一个10分钟,一个走廊上只能有一张桌子移动,那么只需要统计各个编号的走廊所占用的次数,如果一个走廊占用2次,那么在这个走廊上就需要2*10分钟,所以,只需要知道一条走廊占用次数最多是多少,然后*10就是结果。
#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 205;
int a[maxn], b[maxn],c[maxn];
int main()
{
#ifdef LOCAL
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
int T, n;
cin >> T;
while (T--)
{
memset(c, 0, sizeof(c));
cin >> n;
for (int i = 0;i < n;i++)
{
cin >> a[i] >> b[i];
if (a[i] > b[i]) swap(a[i], b[i]);
for (int j = (a[i] + 1) / 2;j <= (b[i] + 1) / 2;j++)
c[j]++;
}
sort(c, c + maxn);
int ans = 10*c[maxn-1];
cout << ans << endl;
}
return 0;
}
一开始,做这道题目时,我首先想到的是HDU 2037,类似于贪心的算法:
部分代码如下:
memset(c, 0, sizeof(c));
cin >> n;
for (int i = 0;i < n;i++)
{
cin >> a[i] >> b[i];
if (a[i] > b[i]) swap(a[i], b[i]);
}
for (int i = 0;i < n;i++)
{
int t = i;
for (int j = i + 1;j < n;j++)
if (a[j] < a[t]) t = j;
if (t != i)
{
swap(a[i], a[t]);
swap(b[i], b[t]);
}
}
int ans = 10;
for (int i = 1;i < n;i++)
{
if (a[i]<b[i-1]) ans+=10;
}
cout << ans << endl;
WA。这对题意没理解完全。比如,对于两个区间[7,9]和[10,11],由于9和10是门对门关系,所以9和10之间的走廊一次只能一个区间使用,正确结果应是2个10分钟,而我的结果实际上是1个十分钟。
后来我又改了一下:
memset(c, 0, sizeof(c));
cin >> n;
for (int i = 0;i < n;i++)
{
cin >> a[i] >> b[i];
if (a[i] > b[i]) swap(a[i], b[i]);
}
for (int i = 0;i < n;i++)
{
int t = i;
for (int j = i + 1;j < n;j++)
if (a[j] < a[t]) t = j;
if (t != i)
{
swap(a[i], a[t]);
swap(b[i], b[t]);
}
}
int ans = 10;
for (int i = 1;i < n;i++)
{
if (b[i - 1] % 2 == 0)
{
if (a[i] < b[i - 1]) ans += 10;
}
else
{
if (a[i] < b[i - 1] + 2) ans += 10;
}
}
cout << ans << endl;
依然WA。这是因为,这种考虑不是最优的。例如:[7,9]、[10,11]和[12,13],最右的解决方案是[7,9]和[12,13]同时进行,[10,11]单独进行,耗时20分钟,而我的结果实际上是30分钟。
所以,一定要理解题意!从走廊入手解决!