http://poj.org/problem?id=1042
有若干个岛屿,每个岛只和前一个岛有路径相连,路径的长度为 ti 个5 分钟的路程,且该路径是单向的,每个岛上都可以钓鱼,岛 i 初始的 5 分钟能钓到的鱼量为 di , 此后的鱼量以每 5 分钟 di 的速度减少,现在从第一个岛开始,问怎样选择停留的方式,才能使在 h 小时内钓到的鱼量最多?
思路一:动态规划
分组背包问题(详见背包问题九讲)
#pragma warning (disable:4786)
#include<iostream>
#include<algorithm>
#include<math.h>
using namespace std;
#define INF -1111111111
int dp[27][199];
int path[30][199];
struct fishing{
int fi; //初始5分钟内的鱼量
int di; //每5分钟减少的鱼量
int ti; //到前一个岛的距离
}fish[27];
int main(){
int n,h,i,j,k,max,last,last_h;
while( scanf("%d",&n) && n ){
memset( dp, 0, sizeof( dp ) );
不能初始化为0
for( i = 1; i < 27; i ++ )
for( j = 0; j < 198; j ++ )
dp[i][j] = INF;
memset( path, 0, sizeof( path ) );
max = 0,last_h = 0;
scanf( "%d", &h );
h = h * 12;
for( i = 1; i <= n; i ++ ){
scanf( "%d", &fish[i].fi );
}
for( i = 1; i <= n; i ++ ){
scanf( "%d", &fish[i].di );
}
for( i = 2; i <= n; i ++ ){
scanf( "%d", &fish[i].ti );
}
//分组背包
for( i = 1; i <= n; i ++ ){
//算出每个岛能钓鱼的最长时间total_t
int total_t = 0;
if( fish[i].fi > 0 ){
if( fish[i].di > 0 ){
if( fish[i].fi % fish[i].di == 0 )
total_t = fish[i].fi / fish[i].di ;
else total_t = fish[i].fi / fish[i].di + 1;
}
else if( fish[i].di <= 0 )
total_t = h;
}
//动归求出停留在 i 岛的时间的最佳方案
for( k = 0; k <= total_t; k ++ ){
//tmp 表示在 i 岛停留 k 个 5 分钟能钓到的鱼量
int tmp = ( 2 * fish[i].fi - ( k - 1 ) * fish[i].di ) * k / 2;
//tt 表示的是总时间 = 从上一个岛到这个岛花费在路上的时间 + 钓鱼的时间 k
int tt = fish[i].ti + k;
for( j = 0; j <= h; j ++ ){
if( j + tt > h )
break;
///如果 >= 则wa,因为题目要求如果有两个方案的钓到的鱼量是一样的,则选择在越考前的岛上停留越多时间的方案
if( dp[i - 1][j] + tmp > dp[i][j + tt] ){
dp[i][j + tt] = dp[i - 1][j] + tmp;
//记录,以便恢复在每个岛上停留的时间信息
path[i][j + tt] = j;
if( dp[i][j + tt] > max ){
max = dp[i][j + tt] ;
//最后一个停留的岛
last = i;
//总共用去的时间
last_h = j + tt;
}
}
}
}
}
int result[27],size = 0;
if( max > 0 ){
for( i = last, j = last_h; i > 0; i -- ){
//计算出在每个岛停留的时间
result[size] = j - path[i][j] - fish[i].ti;
j = path[i][j];
size ++;
}
//按题目要求,剩下的时间都算停留在第一个岛上
if( h - last_h > 0 )
result[size - 1] = result[size - 1] + h - last_h;
printf( "%d",result[size - 1] * 5 );
for( i = size - 2; i >= 0; i -- ){
printf( ", %d",result[i] * 5 );
}
}
//所有岛的鱼量都为1的边界情况
else{
if( h - last_h > 0 )
printf("%d",(h - last_h) * 5);
size ++;
}
while( size < n ){
printf( ", 0");
size ++;
}
printf("\n");
printf( "Number of fish expected: %d\n\n",max );
}
return 0;
}
思路二:贪心