最近开始重读刘汝佳的黑书,从最开始的算法开始吧,毕竟好久没搞了,废话不多说,我们来看看枚举吧
关于枚举的说明,大家可以看看刘汝佳老师的《算法艺术及信息学竞赛》和配套课件,我就不多说了
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 }