HDU 1227 dp距離和最小,中位數的應用
阿新 • • 發佈:2019-02-15
在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; }