1. 程式人生 > >UVA 11134 Fabled Rooks(貪心的妙用+memset誤用警示)

UVA 11134 Fabled Rooks(貪心的妙用+memset誤用警示)

\n UC 錯誤 百度 函數傳參 用法 min 開始 !=

題目鏈接:

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)

而第二種用法可以出現在初始化結構體中。

UVA 11134 Fabled Rooks(貪心的妙用+memset誤用警示)