贪心 POJ1230

题目:

题目链接

  在二维坐标中,给出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;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值