题目链接:https://vjudge.net/contest/279984#problem/G
题目大意:就是说魔术师要穿墙表演,一次表演最多能穿k个墙。一共有n行墙在map上放置,下面n行是墙的第一块和最后一块砖的左上角的坐标。然后让我们判断最少去掉几堵墙能使魔术师从上往下任意挑选一列都能穿墙成功。
思路:从当前超过k堵墙的列开始,到墙的末尾,最长的墙对整个墙的布局的影响最大。所以就拆这个所谓最长的墙。
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <string.h>
using namespace std;
struct node
{
int beginx,beginy;
int endx,endy;
};
int main()
{
node a[105];
int c[105];
int t;
int n,k;
int max_;
int tempr;
int tempid;
int tempc;
int ans;
scanf("%d",&t);
while(t--)
{
max_=-1;
ans=0;
scanf("%d%d",&n,&k);
for(int i=0;i<n;i++)
{
scanf("%d%d%d%d",&a[i].beginx,&a[i].beginy,&a[i].endx,&a[i].endy);
if(a[i].beginx>a[i].endx)//因为题目没有说给的坐标一定是末尾在后
swap(a[i].beginx,a[i].endx);
if(max_<a[i].endx)
max_=a[i].endx;//这里就是记录所有的墙中最靠右的右端点
}
memset(c,false,sizeof(c));//这个c数组是记录每一列有多少个墙
for(int i=0;i<n;i++)
{
for(int j=a[i].beginx;j<=a[i].endx;j++)
c[j]++;
}
for(int i=0;i<=max_;i++)
{
if(c[i]<=k)//如果当前列的墙的个数小于k,那么就继续循环
continue;
tempc=c[i]-k;//否则,tempc记录这一列多了多少堵墙
while(tempc--)
{
tempr=-1;//这个是用来记录墙的长度最长的那个墙的右端点
for(int j=0;j<n;j++)
{
if(a[j].beginx<=i&&a[j].endx>=i&&tempr<a[j].endx)//这里就是说,我们要找的要拆的墙必须是i列被包含在其中,并且右端点是最靠右的(也就是从当前列开始墙的长度是最长的那堵墙)
{
tempr=a[j].endx;//记录所谓最长的墙的右端点
tempid=j;//记录最长的墙的位置(也就是这堵墙是哪一行的)
}
}
for(int j=a[tempid].beginx;j<=a[tempid].endx;j++)//我们拆掉第tempid行的墙,然后影响的列的墙数也要相应改变
{
c[j]--;
}
a[tempid].endx=-1;//被拆的那行墙要pass掉
ans++;//到这里已经拆掉了一堵墙,然后结果加1
}
}
printf("%d\n",ans);
}
return 0;
}