您的位置:首页 > 其它

HDU 1227 Fast Food DP

2013-12-14 11:08 330 查看
http://acm.hdu.edu.cn/showproblem.php?pid=1227

题目大意:

n个饭店在一条直线上,要在这条直线上建立k个仓库,使各个仓库到商店距离和最小。(仓库可以自己选择到哪个商店)

看题解的。。。嗯先存着,以后在来自己做一遍。

下面转自

http://blog.sina.com.cn/s/blog_7ef869630100uzhj.html

仓库要建在商店的位置,也就是说,它一定在某个商店的坐标处;

首先:

我们可以将一下n个商店的位置存入dis[]数组(这里注意,这里说的是位置,我们可以想象,highway当做一个数轴来看,那么dis[i]就代表第i个商店在数轴上的坐标,就是位置,它不代表距离);

然后:

我们要算出从第i个商店到第j个商店之间建一个仓库之后又增加的距离case[i][j],这里要明白,从第i个商店到第j个商店建一个仓库,这个仓库所建的位置一定是dis[(i+j)/2],即建在它的中位数处,所以,这个增加值就是case[i][j]=abs(dis[k]-dis[(i+j)/2])(i<=k<=j);

接下来找dp[i][j];dp[i][j]代表前j个商店建i个仓库的最小距离;

下面就是最难理解的一步了,动态转移方程的寻找,

不好理解就在于有多个阶段,每个阶段都有多个状态,每个阶段的初始值都是不确定的,我们要把它初始为一个尽可能大的数,要找dp[i][j],首先dp[i][j]=10000000(尽可能的大);然后找前一个状态,dp[i-1][m]

为啥是m呢?因为,上一个状态的仓库数是一定的,肯定是比该状态少1,但是商店数就是不确定的了,它最小是

i-1,最大是j-1,即m的范围就是(i-1<=m<=j-1),找到上个状态后,再加上一个增加值,这个增加值是从m+1

到j之间建一个仓库所增加的距离,即case[m+1][j];该状态是dp[i-1][m]+case[m+1][j];那么dp[i][j]就是两值得最小,每次m的改变就会将最小的存入dp[i][j],最后一次的更新,得到该状态的最小值;

这样,我们就找到了状态转移方程

dp[i][j]=MIN(dp[i-1][m]+case[m+1][j]),(i-1<=m<=j-1);

#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const int MAXN=205;
int pos[MAXN];
int cost[MAXN][MAXN];
int dp[42][MAXN];
int main()
{
int n,m;
int kase=1;
while(scanf("%d%d",&n,&m),n ||m )
{
for(int i=1;i<=n;i++)
scanf("%d",&pos[i]);

for(int i=1;i<=n;i++)         //cost[i][j]表示从i~j中新建立一个仓库增加的距离
{							//在第i和j个商店之间建立仓库必在其中位数处,即pos[(j+i)/2]
for(int j=1;j<=n;j++)
{
cost[i][j]=0;
for(int k=i;k<=j;k++)
cost[i][j]+=abs(pos[k]-pos[(j+i)>>1]);
}
}

//设dp[i][j]为前j个商店建立m个仓库的最小距离
for(int i=1;i<=n;i++)
dp[1][i]=cost[1][i];

for(int i=2;i<=m;i++)
{
for(int j=i;j<=n;j++)
{
dp[i][j]=10000000;
for(int k=i-1;k<=j-1;k++)
dp[i][j]=min(dp[i][j],dp[i-1][k]+cost[k+1][j]);
}
}

printf("Chain %d\n",kase++);
printf("Total distance sum = %d\n\n",dp[m]
);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: