HDU 1227 dp距离和最小,中位数的应用



在n个商店中建m个仓库,使各个商店到仓库的路程之和最小,商店到哪个仓库是有选择的,
总之路程之和要最小!

思路:


从第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]=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);



中位数证明:

从n个数中找出一个点使其他点到该点的距离之和最小

个人理解
中位数证明:
5个一维坐标 a,b,c,d,e(a<=b<=c<=d<=e)
以a作点:b+c+d+e-4*a
以b作点:c+d+e-3*b+b-a=c+d+e-2*b-a
以c作点:d+e-b-a
以d做点:e+2*d-a-b-c

通过做差法比较大小可知以c点作该点距离和最小



当然也可以暴力求出某一段的距离和的最小值


心得:

做这道题时总是想着利用好 j 这个点即想成了j作为或不作为仓库,这时还要标记前一个仓库的位置很很是麻烦。

有时候也要利用j点之前的点进行dp的推导:此题就没有只是单纯的利用j点进行。


#include<bits/stdc++.h>

using namespace std;

const int maxn=220;
const int INF=99999999;

int dis[maxn],dp[maxn][maxn],cost[maxn][maxn];

int main()
{

    //freopen("input.txt","r",stdin);
    int n,k;
    int cases=0;
    while(scanf("%d%d",&n,&k))
    {
        int i,j,m;
        if(n==0 && k==0)
            break;
        for(i=1; i<=n; i++)
            scanf("%d",&dis[i]);

        for(i=1; i<=n; i++)
            for(j=i; j<=n; j++)
            {
                cost[i][j]=0;
                for(m=i; m<=j; m++)
                    cost[i][j]+=abs(dis[m]-dis[(i+j)/2]);
            }
        for(i=1; i<=n; i++)
            dp[1][i]=cost[1][i];

        for(i=2; i<=k; i++)
            for(j=i; j<=n-k+i; j++)
            {
                dp[i][j]=INF;
                for(m=i-1; m<=j-1; m++)
                    dp[i][j]=min(dp[i][j],dp[i-1][m]+cost[m+1][j]);
            }
        printf("Chain %d\nTotal distance sum = %d\n\n",++cases,dp[k][n]);
    }
    return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值