Uva 11134 传说中的车 贪心的思维

题目大意:

在一个n*n的棋盘上放置n个车,使得它们之间都不能互相攻击(任意两个车都不能同行或同列),并且,对于第i个车,限制它只能放在一个矩形区域内,(xli, yli),这个矩形的左上角顶点坐标是(xli, yli),右下角顶点坐标是 (xri, yri), 1 ≤ i ≤ n, 1 ≤ xli ≤ xri ≤ n, 1 ≤ yli ≤ yri ≤ n.

分析:
两个车相互攻击的条件是在同一行或列,可以看出,行和列是无关的,所以可以分解成两个一维问题。
问题就转化为在【1,n】选择n个数,使得第i个整数在闭区间【n1i,n2i】内。
思路:
法一:
一开始想的是:因为要把1-n分给这n个区间嘛,所以先把区间排序,然后按顺序依次分配1—n呗,排序规则是先按右端点r排序,再按左端点l排序,然后再依次赋值。这样我以为是正确的,但是WA了,后来想了想,确实不对,比如[1,8],[2,2]这样的话[2,2]在前面,那么[2,2]分配了1这个数,显然是不对的(其实这种排序思路是正确的,只是我的赋值方法是错的,只需要从每个区间的左端开始一次判断赋值就对了)。
法二:
我之后又换了中排序方法,先按l排序,再按r排序。这样从1-n直接赋值有个问题,有的区间跨度很大,但是它却提早赋了一个比较小的数,这样就错了,但是可以用优先队列来维护。
法三:
Lrj的代码给出的思路是:对于每个赋值的数【1,n】,每次找出合适的区间且b值最小,时间复杂度是O(n^2),这和法一排序的思想是一样的!

法一:0ms

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=5005;
typedef struct node
{
    int l,r,id;
};
bool cmp(const node& a,const node& b)
{
    if(a.r==b.r)return a.l<b.l;
    return a.r<b.r;
}
bool vis[N];
int n;
bool solve(node* a,int* ans)
{
    int j;
    memset(vis,0,sizeof(vis));
    for(int i=0;i<n;i++){
        for(j=a[i].l;j<=a[i].r;j++)
            if(!vis[j]){
                vis[j]=1;
                ans[a[i].id]=j;
                break;
            }
        if(j>a[i].r)return 0;
    }
    return 1;
}

node x[N],y[N];
int ansx[N],ansy[N];
int main()
{
    //freopen("f.txt","r",stdin);
    while(~scanf("%d",&n)&&n){
        for(int i=0;i<n;i++){
            scanf("%d%d%d%d",&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)){
            printf("IMPOSSIBLE\n");continue;
        }
        for(int i=0;i<n;i++)
            printf("%d %d\n",ansx[i],ansy[i]);
    }
    return 0;
}

法二:优先队列 20ms

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int N=5005;
struct node
{
    int l,r,id;
    bool operator < (const node& rhs)const{
        if(l==rhs.l)return r>rhs.r;
        return l>rhs.l;
    }
};
int n;
bool solve(node* a,int* ans)
{
    priority_queue<node>q;
    for(int i=0;i<n;i++)q.push(a[i]);
    int cur=1;
    while(!q.empty()){
        node t=q.top();q.pop();
        if(t.r<cur)return 0;
        if(t.l<cur){
            t.l=cur;
            q.push(t);continue;
        }
        if(t.l!=cur)return 0;
        ans[t.id]=cur;
        cur++;
    }
    return 1;
}
node x[N],y[N];
int ansx[N],ansy[N];
int main()
{
    //freopen("f.txt","r",stdin);
    while(~scanf("%d",&n)&&n){
        for(int i=0;i<n;i++){
            scanf("%d%d%d%d",&x[i].l,&y[i].l,&x[i].r,&y[i].r);
            x[i].id=y[i].id=i;
        }

        if(!solve(x,ansx)||!solve(y,ansy)){
            printf("IMPOSSIBLE\n");continue;
        }
        for(int i=0;i<n;i++)
            printf("%d %d\n",ansx[i],ansy[i]);
    }
    return 0;
}

法三:O(n^2) 150ms

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int N=5005;

bool solve(int* a,int* b,int* c,int n)
{
    //memset(c,-1,sizeof(c)); 这里要用fill,因为c是指针
    fill(c,c+n,-1);
    for(int col=1;col<=n;col++){
        int rook=-1,minb=n+1;
        for(int i=0;i<n;i++)
            if(c[i]<0&&b[i]<minb&&col>=a[i])rook=i,minb=b[i];
        if(rook<0||col>minb)return 0;
        c[rook]=col;
    }
    return 1;
}
int x1[N],x2[N],y1[N],y2[N],ansx[N],ansy[N],n;
int main()
{
    //freopen("f.txt","r",stdin);
    while(~scanf("%d",&n)&&n){
        for(int i=0;i<n;i++){
            scanf("%d%d%d%d",&x1[i],&y1[i],&x2[i],&y2[i]);
        }
        if(!solve(x1,x2,ansx,n)||!solve(y1,y2,ansy,n)){
            printf("IMPOSSIBLE\n");continue;
        }
        for(int i=0;i<n;i++)
            printf("%d %d\n",ansx[i],ansy[i]);
    }
    return 0;
}

posted @ 2016-05-10 20:19  HARD_UNDERSTAND  阅读(182)  评论(0编辑  收藏  举报