UVA 11134 Fabled Rooks (贪心)

题意:你的任务是在n*n(1<=n<=5000)的棋盘上放n辆车,使得任意两辆车不相互攻击,且第i辆车在一个给定的矩形R之内(从左上角到右下角)。

1.题中最关键的一点是每辆车的x坐标和y坐标可以分开考虑(他们互不影响),不然会变得很复杂,则题目变成两次区间选点问题:使得每辆车在给定的范围内选一个点,任何两辆车不能选同一个点。

2.本题另外一个关键点是贪心法的选择,贪心方法:对所有点的区间,按右端点从小到大排序;每次在一个区间选点的时候,按从左到右选没有被前面区间选过的点。(从这个区间开始选最大程度的防止了以后的区间没有点可以选(因为右端点选的是最小的))

错误的贪心方法:把所有区间按左端排序,然后每次选能选的最左边的。反例:[1,1],[1,3],[2,2];(这种贪心发并不能保证以后的区间有点可以选,某些区间可能更长,取后面的点更合适)

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

struct node{
int l,r,id;
}x[5500],y[5500],ans[5500],ansx[5500],ansy[5500];

bool cmp(node a,node b){
    return a.r<b.r;
}

bool cmp1(node a,node b){
    return a.id<b.id;
}

int n;
bool vis[5500];


bool solve(node *a,node *ans){
    memset(vis,0,sizeof(vis));
    int i,j;
    for(i=0;i<n;i++){
        for(j=a[i].l;j<=a[i].r;j++){
            if(vis[j]) continue;
            break;
        }
        if(j>a[i].r) return false;
        ans[i].l=j;//将其用来保存答案
        ans[i].id=a[i].id;
        vis[j]=true;
    }
    return true;
}

int main()
{
    ios::sync_with_stdio(false);cin.tie(0);
    while(cin>>n&&n!=0){

        for(int i=0;i<n;i++){
            cin>>x[i].l>>y[i].l>>x[i].r>>y[i].r;
            x[i].id=y[i].id=i;
        }

        sort(x,x+n,cmp);
        sort(y,y+n,cmp);

        if(solve(x,ansx)&&solve(y,ansy)){
            sort(ansx,ansx+n,cmp1);
            sort(ansy,ansy+n,cmp1);
            for(int i=0;i<n;i++)
            {
                cout<<ansx[i].l<<" "<<ansy[i].l<<endl;
            }

        }
        else cout<<"IMPOSSIBLE"<<endl;

    }

    return 0;
}
原文地址:https://www.cnblogs.com/Fy1999/p/9386786.html