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
",row[i],col[i]);
 30             }
 31         } 
 32         else
 33             printf("IMPOSSIBLE
");
 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
",row[i],col[i]);
 91             }
 92         }
 93         else
 94             printf("IMPOSSIBLE
");
 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