zoukankan      html  css  js  c++  java
  • uva 11134 fabled rooks (贪心)——yhx

    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 (xri; yri), where 1  i  n, 1  xli 
    xri  n, 1  yli  yri  n.
    • No two rooks can attack each other, that is no two rooks
    can occupy the same column or the same row.
    Input
    The input consists of several test cases. The rst line of each
    of them contains one integer number, n, the side of the board. n lines follow giving the rectangles
    where the rooks can be placed as described above. The i-th line among them gives xli, yli, xri, and
    yri. The input le is terminated with the integer `0' on a line by itself.
    Output
    Your task is to nd such a placing of rooks that the above conditions are satis ed and then output n
    lines each giving the position of a rook in order in which their rectangles appeared in the input. If there
    are multiple solutions, any one will do. Output `IMPOSSIBLE' if there is no such placing of the rooks.


    因为行和列并没有什么关系,所以只要把问题分成两个,如果都能满足,再进行配对即可。

    那么问题就变成了在[1,n]上有n个区间,把n个整数恰好不重不漏地分配到每个区间。

    很明显用贪心。

     1 #include<cstdio>
     2 #include<cstring>
     3 struct qj
     4 {
     5     int l,r,num;
     6 }q1,q2;
     7 qj a1[5010],a2[5010];
     8 int p1[5010],p2[5010],n;
     9 bool xy(qj a,qj b)
    10 {
    11     return a.l<b.l||(a.l==b.l&&a.r<b.r);
    12 }
    13 void st1(int l,int r)
    14 {
    15     int i,j,k;
    16     qj mid=a1[(l+r)/2];
    17     i=l;
    18     j=r;
    19     do
    20     {
    21         while (xy(a1[i],mid)) i++;
    22         while (xy(mid,a1[j])) j--;
    23         if (i<=j)
    24         {
    25             p1[a1[i].num]=j;
    26             p1[a1[j].num]=i;
    27             q1=a1[i];
    28             a1[i]=a1[j];
    29             a1[j]=q1;
    30             i++;
    31             j--; 
    32         }
    33     }
    34     while (i<=j);
    35     if (l<j) st1(l,j);
    36     if (i<r) st1(i,r);
    37 }
    38 void st2(int l,int r)
    39 {
    40     int i,j,k;
    41     qj mid=a2[(l+r)/2];
    42     i=l;
    43     j=r;
    44     do
    45     {
    46         while (xy(a2[i],mid)) i++;
    47         while (xy(mid,a2[j])) j--;
    48         if (i<=j)
    49         {
    50             p2[a2[i].num]=j;
    51             p2[a2[j].num]=i;
    52             q2=a2[i];
    53             a2[i]=a2[j];
    54             a2[j]=q2;
    55             i++;
    56             j--; 
    57         }
    58     }
    59     while (i<=j);
    60     if (l<j) st2(l,j);
    61     if (i<r) st2(i,r);
    62 }
    63 int main()
    64 {
    65     int i,j,k,m,p,q,x,y,z;
    66     bool ok;
    67     while (scanf("%d",&n)&&n)
    68     {
    69         for (i=1;i<=n;i++)
    70         {
    71             scanf("%d%d%d%d",&q1.l,&q2.l,&q1.r,&q2.r);
    72             p1[i]=p2[i]=q1.num=q2.num=i;
    73             a1[i]=q1;
    74             a2[i]=q2;
    75         }
    76         st1(1,n);
    77         st2(1,n);
    78         ok=1;
    79         for (i=1;i<=n;i++)
    80           if (a1[i].l>i||a1[i].r<i||a2[i].l>i||a2[i].r<i)
    81           {
    82               ok=0;
    83               break;
    84           }
    85         if (ok)
    86           for (i=1;i<=n;i++)
    87             printf("%d %d
    ",p1[i],p2[i]);
    88         else
    89           printf("IMPOSSIBLE
    ");
    90     }
    91 }
    View Code

    以上是经典的错误答案。(反正我开始就是这么错的)

    把区间按左端点排序,第i个区间放整数i。

    反例:[1,1],[1,3],[2,2]。照这个贪心思路找不到解。

     1 #include<cstdio>
     2 #include<cstring>
     3 #define MS(a) memset(a,0,sizeof(a))
     4 int l1[5010],r1[5010],l2[5010],r2[5010],p1[5010],p2[5010];
     5 int main()
     6 {
     7     int i,j,k,m,n,p,q1,q2,x,y,z,min1,min2;
     8     bool ok;
     9     while (scanf("%d",&n)&&n)
    10     {
    11         MS(p1);
    12         MS(p2);
    13         for (i=1;i<=n;i++)
    14           scanf("%d%d%d%d",&l1[i],&l2[i],&r1[i],&r2[i]);
    15         ok=1;
    16         for (i=1;i<=n;i++)
    17         {
    18             q1=q2=-1;
    19             min1=min2=1000000;
    20             for (j=1;j<=n;j++)
    21             {
    22                 if (p1[j]==0&&l1[j]<=i&&r1[j]>=i&&r1[j]<min1)
    23                 {
    24                     q1=j;
    25                     min1=r1[j];
    26                 }
    27                 if (p2[j]==0&&l2[j]<=i&&r2[j]>=i&&r2[j]<min2)
    28                 {
    29                     q2=j;
    30                     min2=r2[j];
    31                 }
    32             }
    33             if (q1==-1||q2==-1)
    34             {
    35                 ok=0;
    36                 break;
    37             }
    38             p1[q1]=i;
    39             p2[q2]=i;
    40         }
    41         if (ok)
    42           for (i=1;i<=n;i++)
    43             printf("%d %d
    ",p1[i],p2[i]);
    44         else
    45           printf("IMPOSSIBLE
    ");
    46     }
    47 }

    正解:把按顺序枚举区间变成按顺序枚举点。对于每个点,找到它能放的、右端点最小的区间。

    若不取这个区间而取另一个右端点更大的区间,会让之后的点选择变少。

  • 相关阅读:
    Maven工程运行环境修改
    Maven中出现org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException错误
    IDEA创建maven_web工程后,右键包没有Servlet、Filter、Listener选项
    Spring中的依赖注入
    什么是JavaBean
    mybatis配置SqlMapConfig.xm时没有提示
    JDK1.8之后匿名内部类访问方法中的局部变量不用加final修饰
    架构、框架和设计模式
    CitrixSQL Server 2016高可用之SQL镜像 SQL Server mirror 带见证服务器
    CitrixPVS BDM启动模式创建虚机 BDM模式部署桌面(精华)
  • 原文地址:https://www.cnblogs.com/SBSOI/p/5575002.html
Copyright © 2011-2022 走看看