题意:
有一个舞台,可以看做网格状的区域,平行于X轴的方向上有n面墙,所有的墙的厚度都是一个单位,但是长度不同,没有一个网格会在多面墙中。魔术师要表演穿墙魔术,他的魔力值有限,只能穿越k面墙。现在观众任意挑选一列(平行于Y轴),魔术师在这一列上,平行于Y轴从最上面穿到最下面。现在给出魔力值k和n面墙的信息,求最少拆几面墙可以让魔术师可以沿任意观众选择的列穿过所有的墙。
思路:
一开始想用贪心的做,但是思维比较浮,直接去想在某一列中,如何让左边和右边都尽可能远,于是思路又跳到搜索上……其实贪心有两个性质:最优子结构和贪心可行性,我没有考虑子结构这个性质。如果把思维沉下来,从左到右扫描,如果这一列没问题就pass,如果有问题就拆能往右延伸的尽可能远的墙。
对,就是酱紫,我们总是动不动就把一个题想的很难,其实,把思维跳回来,多从基础的角度分析,仔细分析,往往有更多的眼界。
还学到的:
这道题一开始WA了,但怎么都找不出错,看了Discuss中一组数据才发现,题目中只说给定一面墙的两个端点(x,y),但没有说一定先给左端点,后给右端点!!!也就是右端点可能在左端点前面给出!!!论思维定势的严重性……
最后,贴代码:
#include <cstdio>
#include <cstring>
using namespace std;
const int MAXN = 105;
int lx[MAXN],ly[MAXN],rx[MAXN],ry[MAXN];
int wall[MAXN];
bool exist[MAXN];
int main()
{
int T,cas;
int n,k,i,j,p;
int max_x;
scanf("%d",&T);
for (cas = 1; cas <= T; ++cas)
{
memset(wall,0,sizeof(wall));
max_x = 0;
scanf("%d %d",&n,&k);
for (i = 0; i < n; ++i)
{
scanf("%d %d %d %d",&lx[i],&ly[i],&rx[i],&ry[i]);
if (rx[i] < lx[i])
{
int tmp = lx[i];
lx[i] = rx[i];
rx[i] = tmp;
}
if (rx[i] > max_x)
max_x = rx[i];
for (j = lx[i]; j <= rx[i]; ++j)
++wall[j];
exist[i] = true;
}
int ans = 0;
for (i = 0; i <= max_x; ++i)
{
if (wall[i] <= k)
continue;
int chai = wall[i] - k;
for (j = 0; j < chai; ++j)
{
int cnt = -1;
for (p = 0; p < n; ++p)
{
if (lx[p] <= i && rx[p] >= i && (cnt == -1 || rx[p] > rx[cnt]) && exist[p] == true)
cnt = p;
}
exist[cnt] = false;
for (p = lx[cnt]; p <= rx[cnt]; ++p)
--wall[p];
}
ans += chai;
}
printf("%d\n",ans);
}
return 0;
}