题意:有一段铁路有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 ID | Submit Time | Judge Status | Pro.ID | Exe.Time | Exe.Memory | Code Len. | Language | Author |
4401271 | 2011-08-12 23:14:23 | Accepted | 2829 | 171MS | 18196K | 1108B | C++ | 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;
}