您的位置:首页 > 其它

POJ1853 Cat (变形与记录路径的01背包)

2015-03-08 22:24 197 查看
DescriptionIn strong winds, sailboats tend to heel leeward (tilt away from the wind) like the one in the picture. Heeling is undesirable for at least two reasons. First, the effective sail area is reduced, as the effective height of the sailis multiplied by the cosine of the angle. Reduced sail area implies reduced speed. Second, the boat may heel to the point that its centre of gravity ceases to be above the hull, causing the boat to capsize.To mitigate these problems, catamarans like the one shown split the hull into two pieces (the port and starboard hulls). This design increases the effective width of the boat. Increased width decreases the vertical mechanical advantage of the sail, thus reducingheeling. Increased width also increases the angle of heeling that can be tolerated before the boat capsizes.Heeling can also be mitigated by having the crew sit or stand on, or even hike out beyond, the windward hull. If you look carefully at the picture you can see the two person crew hiking to windward.At some wind velocity, even these measures are insufficient to keep the boat upright. A skipper's only choice (other than to capsize) is to let out the sail, which reduces its effective horizontal dimension much as heeling reduces its vertical dimension. Aswith heeling, this action causes loss of speed. If the boat heels sufficiently, it may not even be possible to let out the sail, as its outer corner may be obstructed by the surface of the water!Reefing is a mechanism for reducing the sail's area. Roller reefing involves wrapping the sail around the boom (much like a window blind) so as to reduce its height. With sufficient reefing, the heeling can be controlled in almost any wind.But reefing involves reduced speed, so our skipper has elected yet another approach. She has decided to beach the boat and pick up some rocks to use as ballast. Ballast is just dead weight added to hull, which tends to counteract heeling. It slows the boata bit (as it rides lower in the water) but not nearly so much as reducing sail area.Given n rocks, you are to compute how to divide them between the port and starboard hulls so that the weight of rocks in each hull is nearly equal.InputInput contains several test cases. Each test case begins with 1 < n <= 100; the number of rocks to be added as ballast. Consider the rocks to be numbered 1 through n. n lines follow; the ith line gives the weight in kg of the ithrock - a positive real number not greater than 100. A line containing 0 follows the last test case.OutputFor each test case, output a singleline giving the numbers of the rocks that should be loaded as ballast into the starboard hull. Assume that the other rocks will be loaded into the port hull. The total weight of ballast in the port hull should not differ from that in the starboard hull by morethan 2%. If there are many solutions, any one will do. There will always be a solution; indeed, there will always be a solution that balances within 1%, but you aren't required to find it.Sample Input
5
10.0
50.0
90.0
38.0
7.1
0
Sample Output
3 5
 目前做得最曲折的一道题。
题目的大概意思就是把一堆数分成两组,使得两组数的和的差值最小,并且输入数据保证两组数的和的差值不会大于较大那组数的2%。
 一开始拿到这道题的时候,没有往动规上面想,因为总感觉dfs可以做出来,而且代码也写出来了,但提交后超时Orz。于是考虑了动态规划。
 若将所有数分成两组,那么一定会有一大一小,而且一定会很逼近平均值。于是这个问题可以转化为“背包上限是平均值,把这些数装入背包中,使得背包中的数和最大”,一个比01背包还简单的问题---装箱问题(自行百度)。
 不过这里还有一个问题,就是数字都是实数,但动态规划要求数组下标是整数,于是我一开始把所有数据都乘了一个100,但是又超内存了OrzOrz。
 于是看了一下网上的题解,大概就是说不要去对数字进行动规,而要对百分比进行动规,求出每个物品所占总重量的百分比(因为物品是不能扔掉的)。问题转化为“背包上限为50(50%),把一些百分比装进包中,使这个百分比和尽量大”,由于误差不会超过2%,所以乘以20000是比较理想的。
 大问题解决了,但还有一个小问题,就是题目要求输出选择的石头的序号,还涉及到了一个记录路径的问题,用path[j]表示到达容量是j的时候加入的物品的序号。然后采用递归方法输出。用STL也可以,但我一直不会调试STL。
dfs代码(超时):
#include <iostream>#include <string.h>#include <stdio.h>#include <cmath>using namespace std;double aim,part,dif,a[1002];int u[1002],flag,n;void dfs(int x){int i;if (flag==1){return;}else if (x>=n){part=0;for (i=0;i<=n-1;i++){if (u[i]==1){part=part+a[i];}}dif=abs(aim-part)/aim;if (dif<=0.02){flag=1;}return;}else if (x<n){u[x]=0;dfs(x+1);if (flag==1){return;}u[x]=1;dfs(x+1);if (flag==1){return;}}}int main(){do{int i,t;flag=0;t=0;memset(u,0,sizeof(u));scanf("%d",&n);for (i=0;i<=n-1;i++){scanf("%lf",&a[i]);t=t+a[i];}aim=t/2.0;dfs(0);for (i=0;i<=n-1;i++){if (u[i]==1){printf("%d ",i+1);}}printf("\n");}while(1);return 0;}
优化后的动态规划(AC)
#include <iostream>#include <stdio.h>#include <string.h>using namespace std;int path[10002],a[102];void print(int now){if (now == 0) return;int i = path[now];print(now - a[i]);printf("%d ",i+1);}int main(){int i,j,n,f[10002],ansnum;double b[102],total;do{memset(f,0,sizeof(f));memset(path,0,sizeof(path));memset(a,0,sizeof(0));memset(b,0,sizeof(0));total=0;scanf("%d",&n);if (n==0){break;}for (i=0;i<=n-1;i++){scanf("%lf",&b[i]);total=total+b[i];}for (i=0;i<=n-1;i++){a[i]=b[i]/total*400020000;}f[0]=1;for (i=0;i<=n-1;i++){for (j=10000;j>=a[i];j--){if (f[j]==0&&f[j-a[i]]==1){f[j]=f[j-a[i]];path[j]=i;\\路径记录关键}}}for (i=10000;i>=4800;i--){if (path[i]!=0){ansnum=i;break;}}print(ansnum);printf("\n");}while(1);return 0;}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  动态规划 dfs poj