最近開始重讀劉汝佳的黑書,從最開始的算法開始吧,畢竟好久沒搞了,廢話不多說,我們來看看枚舉吧
關於枚舉的說明,大家可以看看劉汝佳老師的《算法藝術及信息學競賽》和配套課件,我就不多說了
UVA1009
很基礎的題目,但還是wa了好幾次

1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<string> 5 #include<cmath> 6 #include<vector> 7 #include<algorithm> 8 #include<map> 9 using namespace std; 10 #define pi acos(-1.0) 11 const int maxn=15; 12 double sx,sy,sz,fx,fy,fz,r[maxn],maxv; 13 int n,sel[maxn],vist[maxn]; 14 struct point 15 { 16 double x,y,z; 17 }; 18 point p[maxn]; 19 double dist(int a,int b) //兩點之間的距離 20 { 21 return sqrt((p[a].x-p[b].x)*(p[a].x-p[b].x)+(p[a].y-p[b].y)*(p[a].y-p[b].y)+(p[a].z-p[b].z)*(p[a].z-p[b].z)); 22 } 23 double distege(int i) //到每條邊之間距離的最小值 24 { 25 double a,b,c; 26 a=min(fabs(p[i].x-sx),fabs(p[i].x-fx)); 27 b=min(fabs(p[i].y-sy),fabs(p[i].y-fy)); 28 c=min(fabs(p[i].z-sz),fabs(p[i].z-fz)); 29 return min(a,min(b,c)); 30 } 31 void distmin() //計算距離的半徑的值 32 { 33 double a,v=0; 34 for(int i=0;i<n;i++) 35 { 36 a=distege(sel[i]); 37 for(int j=0;j<i;j++) 38 { 39 a=min(a,dist(sel[i],sel[j])-r[sel[j]]); 40 } 41 r[sel[i]]=(a<0)? 0:a; 42 if(a<=0) continue; 43 v+=(4.0/3*pi*r[sel[i]]*r[sel[i]]*r[sel[i]]); 44 } 45 maxv=max(maxv,v); 46 } 47 void dfs(int cnt) 48 { 49 if(cnt==n) 50 distmin(); 51 for(int i=0;i<n;i++) 52 { 53 if(vist[i]) continue; 54 sel[cnt]=i; 55 vist[i]=1; 56 dfs(cnt+1); 57 vist[i]=0; 58 } 59 } 60 int main() 61 { 62 int te=1; 63 while(cin>>n) 64 { 65 if(n==0) break; 66 cin>>sx>>sy>>sz>>fx>>fy>>fz; 67 for(int i=0;i<n;i++) 68 cin>>p[i].x>>p[i].y>>p[i].z; 69 maxv=0; 70 memset(vist,0,sizeof(vist)); 71 dfs(0); 72 printf("Box %d: %.0lf\n\n",te++,((fabs((sx-fx)*(sy-fy)*(sz-fz)))-maxv)); 73 } 74 return 0; 75 }
枚舉+DP(01背包問題)
Tyvj1013
這題要同時考慮兩個方面,一方面是要找到的MM最多,同時又需要花費的時間最少,開了一個三維數組,直接進行DP,裸裸的01背包

1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 #include<string> 6 #include<vector> 7 #include<algorithm> 8 #include<map> 9 using namespace std; 10 const int maxn=100+1; 11 int rmb[maxn],rp[maxn],time0[maxn]; 12 int n,m,r; 13 struct point 14 { 15 int sum,time0; 16 }; 17 point p[maxn][maxn]; 18 int main() 19 { 20 int n; 21 while(cin>>n) 22 { 23 memset(p,0,sizeof(p)); 24 for(int i=1;i<=n;i++) 25 cin>>rmb[i]>>rp[i]>>time0[i]; 26 cin>>m>>r; 27 for(int i=1;i<=n;i++) 28 { 29 for(int j=m;j>=rmb[i];j--) 30 { 31 for(int k=r;k>=rp[i];k--) 32 { 33 if(p[j][k].sum>p[j-rmb[i]][k-rp[i]].sum+1) 34 { 35 p[j][k].sum=p[j][k].sum; 36 p[j][k].time0=p[j][k].time0; 37 } 38 else if(p[j][k].sum<p[j-rmb[i]][k-rp[i]].sum+1) 39 { 40 p[j][k].sum=p[j-rmb[i]][k-rp[i]].sum+1; 41 p[j][k].time0=p[j-rmb[i]][k-rp[i]].time0+time0[i]; 42 } 43 else 44 { 45 p[j][k].sum=p[j][k].sum; 46 if(p[j][k].time0>p[j-rmb[i]][k-rp[i]].time0+time0[i]) 47 p[j][k].time0=p[j-rmb[i]][k-rp[i]].time0+time0[i]; 48 } 49 } 50 } 51 } 52 cout<<p[m][r].time0<<endl; 53 } 54 return 0; 55 }
惡心枚舉:
這可能是我至今為止做的最惡心的一道枚舉題了,果然黑書就是與眾不同啊,劉汝佳大牛的題目第二道題目就卡了我三天,其實並沒有做出來,只是閱讀懂了那份代碼
沒有其他理由,就是自己太弱了,為了研一能去打最后一次區域賽,必須好好努力了,真的太菜了,但最后不得不說,黑書果然是算法之王,經典中的經典
鏈接:http://poj.org/problem?id=1116
題意:
魯濱遜在一個遙遠的孤島上獨自生活。一天,一艘裝載着許多珍貴圖書的輪船在島附近失事。通常在這種情況下,羅賓遜會把船上有用的東西從殘骸里搶救出來運到他住的島上。這一次,他帶回來了一箱書。 有了這些書,魯濱遜決定做一個書架,進而建立自己的藏書室。他在石頭牆上鑿了一個矩形壁龕, 把一些栓釘入牆體,然后找來一些木板分別架在兩個水平的栓子上做成書架。 不巧的是,魯濱遜忽然發現有一本珍貴的舊書特別大,根本無法放進他現在架好的書架里。他仔細量了一下這本大部頭的高和厚,想改造一下他的書架,以便於把這本書也放進去(別忘了,書架是做在牆里面的,不能超出范圍)。下面是一些改造的操作方法: 把架子留在原地不動; 把木板向左移或者向右移; 把木板鋸掉一段后向左或向右移; 把栓子釘到與原來位置處於同一水平線的另一個位置,並把木板左移或者右移; 把木板鋸掉一段,移動某一個栓子到同一個水平線上另一個位置,並把木板左移或者右移; 把木板和兩個栓子一起拿掉。 當木板被兩個栓子架住,並且木板的中心在兩個栓子之間或恰在一個栓子上方時,這個書架的放置是穩定的。魯濱遜開始設計的藏書室里所有的書架都是穩定放置的。木板的長度都是整數,單位是英寸。他只能做到以英寸的精度切割木板,因為他的測量工具不夠精確。在你的改造中,所有的書架必須始終是穩定放置的。 你要找到一個方案來改造魯濱遜的藏書室,以便於把那本古老的大書放進去,而且要使改動盡量的少。你要盡量減少移動的栓子數目(操作4、5每次移動一個栓子,操作6每次移動兩個)。如果有幾種不同的辦法達到這個要求,那么你要在其中找到浪費木板長度最小的一個方案(操作3、5各切割掉一定長度,操作6把整個木板的長度都浪費了)。木板的厚度和栓子的直徑忽略不計。 那本大書只能豎直放置,它的全部厚度都要位於木板上,而且只可以碰到其它木板或栓子的邊緣。
輸入 輸入文件的第一行有四個整型數XN,YN,XT,YT,用空格隔開。他們代表了壁龕的寬和高,以及大書的厚和高,單位為英寸(1 <= XN, YN, XT, YT <= 1000). 輸入文件的第二行有一個整型數N(1 <= N <= 100)代表了書架的數量。下面的N行每行都給出一個架子的信息。每行的五個整型數yi, xi, li, x1i, x2i用空格隔開,其中:yi (0 < yi < YN) 表示第i個架子距離壁龕底部的高度;xi (0 <= xi < XN) 表示第i個架子木板左端到壁龕左邊的距離;li (0 < li <= XN - xi) 表示第i個架子木板的長度;x1i (0 <= x1i <= li/2) 表示第i個架子木板左端到支撐它的左邊一個栓子的距離;x2i (li/2 <= x2i <= li; x1i < x2i) 表示第i個架子木板左端到右面一個栓子的距離,以上所有數據的單位都是英寸。 所有的架子都位於不同的高度並且放置穩定。所有輸入數據一定有解。
輸出 輸出文件中應包含兩個整型數,中間用一個空格隔開。第一個是要移動的栓子數目的最小值,第二個是按照這個方案要浪費掉的木板總長的最小值。
input: 11 8 4 6
4
1 1 7 1 4
4 3 7 1 6
7 2 6 3 4
2 0 3 0 3
output: 1 3
下面貼上自己看懂之后加上注釋的代碼:

1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 #include<string> 6 #include<vector> 7 #include<algorithm> 8 #include<map> 9 #include<stack> 10 #include<queue> 11 using namespace std; 12 const int maxn=100+10; 13 struct point 14 { 15 int y,x,len,x1,x2; 16 }; 17 point a[maxn]; 18 int xn,Yn,xt,yt; 19 int n; 20 int optPegs=20000,optCost=10000; 21 22 //按照y從小到大進行排序 23 bool cmp(point p1,point p2) 24 { 25 return p1.y<p2.y; 26 } 27 28 //放在第k塊木板上的書,起始位置為x,栓子的最小移動數量及在滿足此條件下的木板最小削去長度 29 void check(int k,int x,int &minPegs,int &minCost) 30 { 31 for(int i=k+1;i<n;i++) 32 { 33 //排除兩種不會阻擋的情況 34 if(a[i].y>=a[k].y+yt) break; 35 if(a[i].x+a[i].len<=x||a[i].x>=x+xt); 36 37 //當書的起始位置大於x2時 38 else if(a[i].x2<=x) 39 { 40 int mx; 41 if(x-a[i].x1<=a[i].x1) mx=2*(x-a[i].x1); 42 else mx=x; 43 if(mx<a[i].len) minCost+=a[i].len-mx; 44 } 45 46 //當x1大於書的結束位置時 47 else if(a[i].x1>=x+xt) 48 { 49 int mx; 50 if(a[i].x2-(x+xt)<=xn-a[i].x2) mx=2*(a[i].x2-(x+xt)); 51 else mx=xn-(x+xt); 52 if(mx<a[i].len) minCost+=a[i].len-mx; 53 } 54 55 //起始位置大於x1,小於x2,結束位置大於x2 56 else if(a[i].x1<=x&&a[i].x2>x&&a[i].x2<x+xt) 57 { 58 if(x==0) 59 { 60 minPegs+=2; 61 minCost+=a[i].len; 62 } 63 else 64 { 65 minPegs++; 66 if(a[i].len>x) 67 minCost+=a[i].len-x; 68 } 69 } 70 71 //起始位置小於x1,終止位置在x1與x2之間 72 else if(a[i].x1>x&&a[i].x1<x+xt&&a[i].x2>=x+xt) 73 { 74 if(x+xt==xn) 75 { 76 minPegs+=2; 77 minCost+=a[i].len; 78 } 79 else 80 { 81 minPegs++; 82 if(a[i].len>xn-(x+xt)) 83 minCost+=a[i].len-(xn-(x+xt)); 84 } 85 } 86 87 //起始位置大於x1,終止位置小於x2 88 else if(a[i].x1<=x&&a[i].x2>=x+xt) 89 { 90 if(x==0&&xt==xn) minPegs+=2; 91 else minPegs++; 92 int mx=x>xn-(x+xt) ? x:xn-(x+xt); 93 if(a[i].len>mx) minCost+=a[i].len-mx; 94 } 95 96 //起始位置小於X1,終止位置大於X2 97 else if(a[i].x1>x&&a[i].x2<x+xt) 98 { 99 minPegs+=2; 100 minCost+=a[i].len; 101 } 102 } 103 } 104 105 //解決書在第k塊木板上的放置問題 106 void solve(int k) 107 { 108 for(int book_l=0;book_l+xt<=xn;book_l++) 109 { 110 int minPegs=0,minCost=0; 111 if(book_l+a[k].len<a[k].x1) continue; 112 if(a[k].x2+a[k].len<book_l+xt) break; 113 if(book_l+a[k].len<a[k].x1||a[k].x2+a[k].len<book_l+xt) continue; 114 if(2*(a[k].x1-book_l)>a[k].len||2*(book_l+xt-a[k].x2)>a[k].len) 115 minPegs++; 116 else if(a[k].x2-book_l>a[k].len||(book_l+xt)-a[k].x1>a[k].len) 117 minPegs++; 118 check(k,book_l,minPegs,minCost); 119 if(minPegs<optPegs||(minPegs==optPegs&&minCost<optCost)) 120 { 121 optPegs=minPegs; 122 optCost=minCost; 123 } 124 } 125 } 126 int main() 127 { 128 while(cin>>xn>>Yn>>xt>>yt) 129 { 130 cin>>n; 131 for(int i=0;i<n;i++) 132 { 133 cin>>a[i].y>>a[i].x>>a[i].len>>a[i].x1>>a[i].x2; 134 a[i].x1+=a[i].x; 135 a[i].x2+=a[i].x; 136 } 137 sort(a,a+n,cmp); 138 for(int i=0;i<n;i++) 139 { 140 if(a[i].y+yt>Yn) break; 141 if(a[i].len>=xt) solve(i); 142 } 143 cout<<optPegs<<" "<<optCost<<endl; 144 } 145 return 0; 146 }