• 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
    ");continue;
            }
            for(int i=0;i<n;i++)
                printf("%d %d
    ",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
    ");continue;
            }
            for(int i=0;i<n;i++)
                printf("%d %d
    ",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
    ");continue;
            }
            for(int i=0;i<n;i++)
                printf("%d %d
    ",ansx[i],ansy[i]);
        }
        return 0;
    }
    
    
  • 相关阅读:
    Java实现寻找最小的k个数
    Java实现寻找最小的k个数
    foruok安晓辉的《程序员,你好哇》,都很不错
    DataSnap的如果网络断线,如何恢复?
    配置QSslConfiguration让客户端程序跳过本地SSL验证
    Linux升级OpenSSL版本
    FMX+Win32,窗口无法保持原样,应该是个bug
    [Nhibernate]二级缓存
    EventBus(事件总线)
    elasticsearch集群搭建实例
  • 原文地址:https://www.cnblogs.com/01world/p/5651213.html
Copyright © 2020-2023  润新知