HDU 2829

题意:有一段铁路有n个站,每个站可以往其他站运送粮草,现在要炸掉m条路使得粮草补给最小,粮草补给的公式是将每个站能收到的粮草的总和。

4----5-----1-----2

Its Strategic Value is 4*5 + 4*1 + 4*2 + 5*1 + 5*2 + 1*2 = 49.

4----5       1-----2

The Strategic Value of the remaining railroad is 4*5 + 1*2 = 22. 

4      5-----1------2

The Strategic Value of the remaining railroad is 5*1 + 5*2 + 1*2 = 17.

初看这题感觉和post office那题好像,所以就直接把状态给设定出来了 dp[i][j]表示到j为止的前面炸了i条路的得到最小总数,显然要先预处理这些边,但是这样的话还是有点问题,就是复杂度,1000*1000*1000这个必然是tle啊,那么来看看转移方程dp[i][j]=min(dp[i-1][k]+cost[k+1][j])(i-1<k<j);看着这个式子是不是很熟悉,对了和四边形不等式dp[i][j]=min(dp[i-1][k]+dp[k][j]+cost[i][j])(i-1<k<j)很像。那么它满足条件吗?主要看后面的cost函数是否递减,cost[i][j+1]-cost[i][j]>0,显然递减,满足条件,可以优化了。不明白四边形不等式的可以去看看这个课件http://wenku.baidu.com/view/be418243a8956bec0975e3bf.html

优化后就1y了,效率好高。将复杂度o(n^3)降到了o(n^2)

Run IDSubmit TimeJudge StatusPro.IDExe.TimeExe.MemoryCode Len.LanguageAuthor
44012712011-08-12 23:14:23Accepted2829171MS18196K1108BC++xym2010
代码

#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=1005;
long long cost[maxn][maxn],dp[maxn][maxn],s[maxn][maxn];
void DP(int n,int m)
{
	long long ans=1000000000000;
	for(int i=0;i<n;i++)
	{
		dp[0][i]=cost[0][i];
		s[0][i]=0;
		s[i][n]=n-2;
	}
	for(int i=1;i<=m;i++)
		for(int j=n-1;j>=0;j--)
		{
			long long tem=10000000000;
			int bin;
			for(int k=s[i-1][j];k<=s[i][j+1];k++)
			{
				if(tem>dp[i-1][k]+cost[k+1][j])
				{
					tem=dp[i-1][k]+cost[k+1][j];
					bin=k;
				}
			}
			s[i][j]=bin;
			dp[i][j]=tem;
		}
		printf("%lld\n",dp[m][n-1]);
		
}
int main()
{
	int n,m;
	long long sum[maxn],tem[maxn];
	while(scanf("%d%d",&n,&m)&&n&&m)
	{
		for(int i=0;i<n;i++)
		{
			scanf("%lld",&tem[i]);
			sum[i]=i==0?tem[i]:(sum[i-1]+tem[i]);
		}
		for(int i=1;i<n;i++)
			cost[0][i]=cost[0][i-1]+sum[i-1]*tem[i];
		for(int i=1;i<n;i++)
			for(int j=i+1;j<n;j++)
			{
				cost[i][j]=cost[i][j-1]+(sum[j-1]-sum[i-1])*tem[j];
			}
			DP(n,m);
	}
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值