题目描述直达:点击打开链接
题目看似不难,用贪心的思想就可以完成。但有若干小陷阱。
1、输入数据<s, t>可能会存在s大于t的情形。
2、<1,3> <4,5>要分两组完成,而<1, 2> <3, 5>只需要一组。
这些,起初就想到了,先看我的思路吧。
大致是这样的,首先需要为房间号x做一个(x+1)/2的映射,创建一个标记数组flag[200][201],第一维表示组号,第二维表示对应的过道占用情形,举个简单例子,flag[0][3]=1表示第1组第3号过道占用,凡是经过房间号5、6的都不能在这一组同时完成。对输入数据<s, t>依次扫描,然后跟现有的每一组标记做对比,如果可以的话,就放到该组完成,否则,跟下一组做对比,这样进行下去。如果直到最后一组也不能同时完成的话,就需要新加一组。
代码看起来有点臃肿。但是自我感觉思路应该没有问题的。可事实证明,只是自己想当然而已。因为提交之后总是WA。
#include <stdio.h>
int flag[201][201];
int main()
{
int nCases, n, i, cnt;
int s, t, p, is_ok, done;
scanf("%d", &nCases);
while (nCases--) {
cnt = 0;
memset(flag, 0, sizeof(flag));
scanf("%d", &n);
while (n--) {
scanf("%d %d", &s, &t);
if (s>t) {
s ^= t; t ^= s; s ^= t;
}
i = 0; done = 0;
while (!done && i<cnt) {
p = (s+1)/2; is_ok = 1;
while (is_ok && p<=(t+1)/2) {
if (flag[i][p]==1)
is_ok = 0;
p++;
}
if (is_ok) {
p = (s+1)/2;
while (p<=(t+1)/2) {
flag[i][p] = 1;
p++;
}
done = 1;
}
i++;
}
if (!done) {
p = (s+1)/2;
while (p<=(t+1)/2) {
flag[cnt][p] = 1;
p++;
}
cnt++;
}
}
printf("%d\n", cnt*10);
}
return 0;
}
想啊想啊想破脑袋。终于想到一个测试用例把前面的思路推翻。<1, 8> <4, 15> <17, 25> <13, 19>
<1, 8>放第一组;<4, 15>放第二组;<17, 25>放第一组;<13, 19>放第三组
好,结果是要分3组完成。可事实上呢,两组就可以完成了,<1, 8> <13, 19>放第一组,<4, 15> <17, 25>放第二组。
为什么会这样呢?在处理每组输入数据时,我是
依次扫描之前的分组情况,导致最终方案会跟输入数据的顺序有关。正确的做法应该是,扫描之前的分组情况,选择加入一个“最合适”的分组。
后来,参考网上大牛们的代码。发现一个不错的思路。
标记数组从二维降到一维,flag[201]。flag[i]表示过道第i个位置的占用总数。最终,占用总数最多的那一个位置就是所需要的分组数目。
#include <stdio.h>
int flag[201];
int main()
{
int nCases, n, i, cnt;
int s, t;
scanf("%d", &nCases);
while (nCases--) {
cnt = 0;
memset(flag, 0, sizeof(flag));
scanf("%d", &n);
while (n--) {
scanf("%d %d", &s, &t);
if (s>t) {
s ^= t; t ^= s; s ^= t;
}
for (i=(s+1)/2; i<=(t+1)/2; i++)
flag[i] += 1;
}
cnt = flag[1];
for (i=2; i<201; i++) {
if (cnt<flag[i])
cnt = flag[i];
}
printf("%d\n", cnt*10);
}
return 0;
}
总结:原始问题该怎么转化?转化后更要确保问题是等价的。动手扣锭之前要思考清楚!