1. 程式人生 > >【動態規劃】[USACO2016 金組]Circular Barn Revisited

【動態規劃】[USACO2016 金組]Circular Barn Revisited

題目描述

After the last debacle involving Farmer John’s circular barn, one would think he had learned his lesson about non-traditional architecture. However, he thinks he can still make his circular barn (from the preceding problem) function properly by allowing multiple cows into each room. To recap, the barn consists of a ring of nn rooms, numbered clockwise from 1…n1…n around the perimeter of the barn (3≤n≤1003≤n≤100). Each room has doors to its two neighboring rooms, and also a door opening to the exterior of the barn.
Farmer John wants exactly riri cows to end up in room ii (1≤r

i≤1,000,0001≤ri≤1,000,000). To herd the cows into the barn in an orderly fashion, he plans to unlock k exterior doors (1≤k≤7), allowing the cows to enter through only those doors. Each cow then walks clockwise through the rooms until she reaches a suitable destination. Farmer John wants to unlock the exterior doors that will cause his cows to collectively walk a minimum total amount of distance after entering the barn (they can initially line up however they like outside the k unlocked doors; this does not contribute to the total distance in question). Please determine the minimum total distance his cows will need to walk, if he chooses the best k such doors to unlock.

INPUT FORMAT (file cbarn2.in):

The first line of input contains nn and kk. Each of the remaining nn lines contain r1…rnr1…rn.

OUTPUT FORMAT (file cbarn2.out):

Please write out the minimum amount of distance the cows need to travel.

SAMPLE INPUT:

6 2
2
5
4
2
6
2

SAMPLE OUTPUT:

14

題目分析

我們令dp(i,j,k)表示第一個位置在i當前放置的位置在j正在選擇了第k個門的位置的最優狀態那麼我們顯然有答案為min{dp(i,j,K)}同時有

dp(i,j,k)=min{dp(i1,t,k1)+val(t,j1,0)}其中val(i,j,k)表示從ij中所有的牛從i出發歸位需要走過的總距離k表示修正值為了特殊處理當k=K的情況dp(i,j,K)=min{dp(i,t,k1)+val(t,j1,0)+val(j,n,0)+val(1,i,nj+1)}

程式碼

#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
const int MAXN = 100;
const long long INF = 1e18+7;
long long dp[MAXN+10][10], sum[MAXN+10];
int n, k;
inline long long val(int l, int r, long long fix){
    long long ret = 0;
    for(int i=l;i<r;i++)
        ret += sum[i] * (i - l + fix);
    return ret;
}
long long solve(int beg){
    for(int i=1;i<k;i++){
        for(int j=1;j<=n;j++) if(~dp[j][i]){
            for(int t=j+1;t<=n;t++){
                if(dp[t][i+1] == -1) dp[t][i+1] = INF;
                dp[t][i+1] = min(dp[t][i+1], dp[j][i]+val(j, t, 0));
            }
        }
    }
    long long ret = INF;
    for(int i=1;i<=n;i++)
        if(~dp[i][k])
            ret = min(ret, dp[i][k]+val(i, n+1, 0)+val(1, beg, n-i+1));
    return ret;
}
int main(){
    scanf("%d%d", &n, &k);
    for(int i=1;i<=n;i++)scanf("%lld", &sum[i]);
    long long ans = INF;
    for(int i=1;i<=n;i++){
        memset(dp, -1, sizeof dp);
        dp[i][1] = 0;
        ans = min(ans, solve(i));
    }
    printf("%lld\n", ans);

    return 0;
}