题目:
在二维坐标中,给出N面墙,给出每面墙的起始坐标和终止坐标,每面墙都是与 x <script type="math/tex" id="MathJax-Element-1">x</script>轴平行的。给出K,现在要去除一些墙,使每一列的墙的数量不多于K。求需要去除的最少的墙数。
- N<100
- K<100
- 坐标都小于100
解法:
利用贪心策略:从左往右扫描每一列,如果这一列不符合要求则对它处理,拆除向右延伸得最长的那面墙。
注意:这道题有很多坑:
- 给出每列墙的时候,可能先给右边的点,然后再给左边的点。
- 并不是每行只有一面墙,可能连续的墙包含几面墙。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
struct wall{
int start,ends;
}w[100+5][100+5];
struct column{
int walls;
int a[100+5];
}c[100+5];
int s[100+5][100+5];
int colu = 0;
bool cmp(const int &i, const int &j)
{
int total_i = w[i][colu].ends ;
int total_j = w[j][colu].ends ;
return total_i > total_j;
}
int main()
{
int cas;
scanf("%d",&cas);
while(cas--)
{
int wa,k;
scanf("%d%d",&wa,&k);
memset(s,0,sizeof(s));
memset(w,0,sizeof(w));
memset(c,0,sizeof(c));
int x[2],y[2];
int max_x = 0;
int max_y = 0;
int sum = 0;
for(int i = 0; i<wa; i++){
scanf("%d%d%d%d",&x[0],&y[0],&x[1],&y[1]);
if(x[0]>x[1]) swap(x[0],x[1]);
max_x = max(max_x, x[1]+1);
max_y = max(max_y, y[0]+1);
for(int m = x[0]+1; m<=x[1]+1; m++){
w[y[0]+1][m].start = x[0]+1;
w[y[0]+1][m].ends = x[1]+1;
}
for(int j = x[0]+1; j<=x[1]+1; j++)
s[y[0]+1][j] = 1;
}
for(int i = 1; i<=max_x; i++)
{
c[i].walls = 0;
for(int j = 1; j<=max_y; j++){
if(s[j][i]){
c[i].a[c[i].walls] = j;
c[i].walls++;
}
}
colu = i;
sort(c[i].a,c[i].a+c[i].walls,cmp);
}
int ans = 0;
for(int i =1; i<=max_x; i++)
{
int m = 0;
while(c[i].walls>k){
while(w[c[i].a[m]][i].start == -2)
m++;
int l = c[i].a[m];
c[i].a[m++] = -2;
for(int j = i; j<=w[l][i].ends; j++){
c[j].walls--;
}
for(int n = i; n<=w[l][i].ends; n++)
w[l][n].start = w[l][n].ends = -2;
ans++;
}
}
printf("%d\n",ans);
}
return 0;
}