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;
}

时间: 2024-10-16 05:21:03

Uva 11134 传说中的车 贪心的思维的相关文章

UVa 11134 传说中的车

https://vjudge.net/problem/UVA-11134 题意:在n*n的棋盘上放n个车,使得任意两个车不相互攻击,且第i个车在一个给定的矩形Ri之内.用4个整数xli,yli,xri,yri来描述第i个矩形. 思路:行和列是不影响的,也就是说第i个棋子放在第几行不会影响它的列数.这样的话我们就可以分别处理行和列.由于棋子被给定了范围,这样的话我们可以用贪心法来解决,按照ri右坐标从小到大排序,然后从左坐标开始选出最小的且未被占据的坐标. 1 #include<iostream>

(白书训练计划)UVa 11134 Fabled Rooks(贪心)

题目地址:UVa 11134 这题因为行与列是无关的,互无影响的.所以可以将行或列分开来计算.这就相当于转化成了在期间[1,n]内选择n个不同的整数,使得第i个整数在闭区间[Li,Ri]内.这就转换成了一个贪心问题了.但是注意不能先按照左端点排序,再按右端点排序,然后尽量往左边放,比如,(1,1),(1,3),(2,2),这样是不对的,应该按右端点为主关键字排序,再按左端点为次关键字排序.看到网上的方法全都是用每次选一个数后,都要在后面的区间中删去这个数,还要用到优先队列..感觉没必要这样做..

UVa 11134 (区间上的贪心) Fabled Rooks

这道题真是WA得我心力交瘁,好讨厌的感觉啊! 简直木有写题解的心情了 题意: n×n的棋盘里,放置n个车,使得任意两车不同行且不同列,且第i个车必须放在给定的第i个矩形范围内.输出一种方案,即每个车的坐标,无解的话则输出“IMPOSSIBLE” 行和列是独立的,所以可以分开处理,将二维的转化成了一维区间上的取点问题: 有一个长度为n的区间,还有n个小区间,求一种方案,在每个小区间的范围取一个点,是的大区间上每个单位1的区间里都有点. 开始写的贪心是错误的: 按区间的左端点从小到大排序,然后右端点

UVa 11134 Fabled Rooks(贪心)

题意  在n*n的棋盘上的n个指定区间上各放1个'车'  使他们相互不攻击   输出一种可能的方法 行和列可以分开看  就变成了n个区间上选n个点的贪心问题  看行列是否都有解就行   基础的贪心问题  对每个点选择包含它的最优未使用空间 #include <bits/stdc++.h> using namespace std; const int N = 5005; int xl[N], yl[N], xr[N], yr[N], x[N], y[N], n; bool solve(int a

UVA 11134 - Fabled Rooks(贪心 / 二分图 + 线段树优化连边)

题目地址:Fabled Rooks 题目大意:n * n 的棋盘上摆了 n <=10^5 个车,让他们两两不攻击,每个车必须摆在一个给定矩形里,给出一个解决方案? 1. 贪心 由于行列互不影响, 所以可以分两遍求.第一遍确定每个车的行数,第二遍确定列数. 以行为例,若从左到右扫描,则按照区间的右端点升序排序,因为如果扫到一个位置两枚棋子都可以放,则选择右端点较小的那个(右端点大的后面还有机会). 2. 二分图匹配 有个毒瘤老师把题目改成了这样:n * n 的棋盘上摆了 n <=10^5 个车,

UVA 11134 Fabled Rooks(贪心的妙用+memset误用警示)

题目链接: https://cn.vjudge.net/problem/UVA-11134 1 /* 2 问题 输入棋盘的规模和车的数量n(1=<n<=5000),接着输入n辆车的所能在的矩阵的范围,计算并输出使得每辆车横竖都不能相互攻击 3 的摆放方法,能则输出每辆车的坐标,不能则输出"IMPOSSIBLE". 4 解题思路 想想怎么将问题分解成几个小问题,不同行不同列的话,将其分成两个一维问题,采用DFS向下搜索,搜的时候注意每个车的 5 行区间和列区间,找到一种则直接

uva 11134 fabled rooks (贪心)——yhx

We would like to place n rooks, 1 n 5000, on a n nboard subject to the following restrictions• The i-th rook can only be placed within the rectan-gle given by its left-upper corner (xli; yli) and its right-lower corner (xri; yri), where 1 i n, 1 xli

01_传说中的车(Fabled Rooks UVa 11134 贪心问题)

问题来源:刘汝佳<算法竞赛入门经典--训练指南> P81: 问题描述:你的任务是在n*n(1<=n<=5000)的棋盘上放n辆车,使得任意两辆车不相互攻击,且第i辆车在一个给定的矩形R之内. 问题分析:1.题中最关键的一点是每辆车的x坐标和y坐标可以分开考虑(他们互不影响),不然会变得很复杂,则题目变成两次区间选点问题:使得每辆车在给定的范围内选一个点,任何两辆车不能选同一个点.  2.本题另外一个关键点是贪心法的选择,贪心方法:对所有点的区间,按右端点从小到大排序:每次在一个区间

UVA - 11134 Fabled Rooks[贪心 问题分解]

UVA - 11134 Fabled Rooks We would like to place n rooks, 1 ≤ n ≤ 5000, on a n × n board subject to the following restrictions The i-th rook can only be placed within the rectan- gle given by its left-upper corner (xli,yli) and its right- lower corner