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

题目链接:

https://cn.vjudge.net/problem/UVA-11134

  1 /*
  2 问题 输入棋盘的规模和车的数量n(1=<n<=5000),接着输入n辆车的所能在的矩阵的范围,计算并输出使得每辆车横竖都不能相互攻击
  3 的摆放方法,能则输出每辆车的坐标,不能则输出"IMPOSSIBLE"。
  4 解题思路 想想怎么将问题分解成几个小问题,不同行不同列的话,将其分成两个一维问题,采用DFS向下搜索,搜的时候注意每个车的
  5 行区间和列区间,找到一种则直接返回,输出对应每辆车的行和列即可。但是超时!!!
  6     使用贪心法,先将所有区间按照右端点的大小进行排序,然后枚举每一个区间,找到一个数k,满足在此区间内,直到所有区间都找到
  7 一个数输出结果或者其中有一个车在其区间内找不到合适的位置则输出IMPOSSIBLE
  8 */
  9 #include<cstdio>
 10 #include<cstring>
 11 const int N = 5050;
 12
 13 int xl[N],xr[N],yl[N],yr[N];
 14 int n;
 15 int row[N],col[N];
 16
 17 int solve(int ans[],int l[],int r[]);
 18
 19 int main()
 20 {
 21     int i;
 22     while(scanf("%d",&n), n != 0){
 23         for(i=0;i<n;i++){
 24             scanf("%d%d%d%d",&xl[i],&yl[i],&xr[i],&yr[i]);
 25         }
 26
 27         if(solve(row,xl,xr) && solve(col,yl,yr)){
 28             for(i=0;i<n;i++){
 29                 printf("%d %d\n",row[i],col[i]);
 30             }
 31         }
 32         else
 33             printf("IMPOSSIBLE\n");
 34     }
 35     return 0;
 36 }
 37
 38 int solve(int ans[],int l[],int r[])
 39 {
 40     int cur,minr;//minr为包含k的区间最小右界(刚开始时初始化为最大,便于寻找最小),cur为放k的最优区间(号)
 41     memset(ans,-1,sizeof(int)*n);
 42     //memset(ans,-1,sizeof(ans));错误用法,详见分析
 43     int k,i;
 44     for(k=1;k<=n;k++){
 45         cur = -1,minr = N;//初始化刚开始时初始化为最大,便于寻找最小
 46         for(i=0;i<n;i++){//枚举每个区间
 47             if(ans[i] < 0 && l[i] <= k && r[i] < minr){
 48             //该区间没有被用过且k大于等于该区间的左边界且最小右边界也在该区间内
 49                 cur = i;//更新 预备将k存放的区间号
 50                 minr = r[i];//缩小右边界,也是贪心法的体现,总是放在可行区间的最右侧
 51             }
 52         }
 53         //没有区间能够放置k或者k不满足在最优区间内
 54         if(cur < 0 || k > minr)    return 0;
 55         //将k放置在cur区间内
 56         ans[cur]=k;
 57     }
 58     return 1;
 59 }
 60
 61 /*DFS搜索,超时!!!
 62 #include<cstdio>
 63 #include<cstring>
 64 struct REC{
 65     int xr,yr,xl,yl;
 66 }rec[5050];
 67
 68 int row[5050],col[5050],n,flag1,flag2;
 69 int bkrow[5050],bkcol[5050];
 70
 71 void dfsrow(int step);
 72 void dfscol(int step);
 73 int main()
 74 {
 75     int i;
 76
 77     while(scanf("%d",&n), n != EOF){
 78         for(i=1;i<=n;i++){
 79             scanf("%d%d%d%d",&rec[i].xl,&rec[i].yl,&rec[i].xr,&rec[i].yr);
 80         }
 81
 82         memset(bkrow,0,sizeof(bkrow));
 83         memset(bkcol,0,sizeof(bkcol));
 84         flag1=flag2=0;
 85         dfsrow(1);
 86         dfscol(1);
 87
 88         if(flag1 && flag2){
 89             for(i=1;i<=n;i++){
 90                 printf("%d %d\n",row[i],col[i]);
 91             }
 92         }
 93         else
 94             printf("IMPOSSIBLE\n");
 95
 96     }
 97     return 0;
 98 }
 99
100 void dfsrow(int step){
101     if(step == n+1){
102         flag1=1;
103         return;
104     }
105
106     int j;
107     for(j=rec[step].xl;j<=rec[step].xr;j++){
108         if(bkrow[j] == 0){
109             bkrow[j]=1;
110             row[step]=j;
111             dfsrow(step+1);
112
113             if(flag1)
114                 return;
115             bkrow[j]=0;
116         }
117     }
118 }
119
120 void dfscol(int step){
121     if(step == n+1){
122         flag2=1;
123         return;
124     }
125
126     int j;
127     for(j=rec[step].yl;j<=rec[step].yr;j++){
128         if(bkcol[j] == 0){
129             bkcol[j]=1;
130             col[step]=j;
131             dfscol(step+1);
132
133             if(flag2)
134                 return;
135             bkcol[j]=0;
136         }
137     }
138 }*/

  解决这道题的过程还是一波三折的,搜索超时,贪心苦思冥想,最后还栽在了初始化函数memset上,可以看到平时大家使用初始化函数初始化数组时都这样写

1.memset(ans,-1,sizeof(int)*n);

2.memset(ans,-1,sizeof(ans));

意即将ans数组中的内存单元全部初始化为-1,其实只有第一种写法是正确的,这里错误的原因是VC函数传参过程中的指针降级,导致sizeof(a),返回的是一个something*指针类型大小的的字节数,如果是32位,就是4字节。(详见百度百科https://baike.baidu.com/item/memset/4747579?fr=aladdin#reference-[1]-982208-wrap

而第二种用法可以出现在初始化结构体中。

原文地址:https://www.cnblogs.com/wenzhixin/p/8758881.html

时间: 2024-12-17 16:22:56

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

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

UVA 11134 Fabled Rooks 贪心

题目链接:UVA - 11134 题意描述:在一个n*n(1<=n<=5000)的棋盘上放置n个车,每个车都只能在给定的一个矩形里放置,使其n个车两两不在同一行和同一列,判断并给出解决方案. 算法分析:刚开始没有思路,后来看了别人的博客有了一点想法.我们把矩形的行和列分开解决,即n个车首先不能放置在同一行,然后判断n个车不能放置在同一列,如果都满足的话,即有正确的方法,否则就不行.那么怎样解决和判断在不在同一行并且是否可行呢,我们针对行而言,把这些行的坐标存入优先队列,首先取出最上面(行的标号

uva 11134 - Fabled Rooks(主要在贪心方法及其实现)

#用到了贪心方法. #这个贪心刚开始想错了方法,后来想到了新的方法,AC 刚开始错在了按左端点升序排序并从左往右取最左端能取的格子,这个方法显然不能符合要求 比如下面这组数据: 2 1 1 3 3 1 1 3 3 2 2 2 2 错误代码: #include<stdio.h> #include<string.h> #include<iostream> #include<algorithm> using namespace std; struct note {

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

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

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 (贪心)——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

Uva 11134 Fabled Rooks (问题分解 + 贪心放置)

题意: 给你n*n的棋盘,让放置n个车 使他们之间并不能相互攻击 附加条件是 给定n个车的放置区间 用左上角和右下角的坐标来表示 解题思路: 首先明确 横向的约束和纵向的约束其实并不互相影响 所以可以对横向和纵向单独求解 把问题变成两个一维的区间选点问题来求解 另外 在取点的时候 有贪心的思路在里面 对于n个区间 应该先选择区间中r最小的区间进行放置可放置的点 可以简单认为这是因为r越小的区间 其选择的灵活性就越低. 我刚开始的时候 是采取了先放置区间长度小的 在放置l小的区间 不正确. cod

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 rectangle given by its left-upper corner (xli, yli) and its rightlower corner (xri, yri), where 1 ≤ i ≤