poj 1160 动态规划

题意:n (n<=300)个村庄,要建设m (m<=30)个邮局,每个村庄使用最近的邮局,问总距离最小是多少?

分析:

 

最初的想法:dp(i, j)表示前j个村庄建设i个邮局,并且第i个邮局建设在第j个村庄的最小距离,

则dp(i, j) = min ( dp(i-1,k) + dist(k,j) )。(i-1<=k<j,  dist(k,j)为在村庄k和村庄j建设邮局,k和j之间的村庄到他们的最小距离)。

由于n>=m,即最优解一定建设了m个邮局,第m个邮局可能建设在第k(m<=k<=n)个村庄,k+1~n的村庄只能到第k个村庄去,

所以答案为min ( dp(m,k)+D(k) )   (m<=k<=n,   D(k)为k+1~n的村庄到k的距离和)。

 

 

const int N = 305, M = 33;
int n, m;
int dp[M][N], a[N];
int dist[N][N];

int d(int i, int j){//在i和j建造邮局,i j之间的村庄到他们的距离
    if(dist[i][j]) return dist[i][j];
    if(j-i<=1) return 0;
    int t = 0, mid = (a[i]+a[j])/2;
    FOE(k, i+1, j-1){
        if(a[k]<=mid) t += a[k]-a[i];
        else t += a[j]-a[k];
    }
    dist[i][j] = t;
    return t;
}

int main(){
    #ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    #endif

    scanf("%d%d", &n, &m);
    FOE(i, 1, n) scanf("%d", &a[i]);
    a[n+1] = 99999999;

    FOE(j, 2, n) {
        dp[1][j] = dp[1][j-1]+(j-1)*(a[j]-a[j-1]);          //cout<<1<<' '<<j<<' '<<dp[1][j]<<endl;
        int t = min(j, m);
        FOE(i, 2, t){
            dp[i][j] = -1;
            FOR(k, i-1, j){
                checkmin(dp[i][j], dp[i-1][k]+d(k, j));
            }           //cout<<i<<' '<<j<<' '<<dp[i][j]<<endl;
        }
    }

    int ans = -1;
    FOE(j, m, n) checkmin(ans, dp[m][j]+d(j,n+1));
    printf("%d\n", ans);

    return 0;
}

 

posted @ 2013-05-30 16:22  心向往之  阅读(150)  评论(0编辑  收藏  举报