【DP】[USACO 2016 February Contest, Gold]Circular Barn Revisited

题目大意

还是这个谷仓,有n(3<=n<=100)个房间。当然,奶牛可能不止n头了。奶牛都在谷仓外面。现在约翰想要让第i个房间关ri(1<=ri<=1000000)头奶牛按顺时针方向走,直到到达合适的房间。这k(1<=k<=7)个门开在哪里,才能使得奶牛们走的路程最少。奶牛在谷仓外可以随意移动,可以随意选择k个门中的任意一个排队,这不计入最终的路程。
输入格式:
输入包含n和k。接下来n行包含r1,r2,……rn,表示每个房间最后容纳的奶牛数目。
输出格式:奶牛们走的最小的总路程。
输入样例:
6 2
2
5
4
2
6
2
输出样例:
14
样例解释:FJ可以打开2号门和5号门。这样,11头奶牛从2号门进入,走过的总距离为8,到达2,3,4号房间。10头奶牛从5号门进入,分别叨叨5号,6号和1号房间,走过的总距离为6.

分析

首先,预处理出 disti,j ,从i开始的j个房间的奶牛都从i从i号门进入所走的总距离。

然后破环为链,进行dp。
fi,j,k 表示第 i 个房间,到这个房间已经有 j 个房间满足条件,已经开了 k 扇门

fi,j,k=min(fil,jl,j1+distil+1,l)

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAXN 100
#define MAXK 7
int n,r[MAXN+10],k;
long long f[MAXN*2+1][MAXN+1][MAXK+1],ans=0x7fffffffffffffffll,dist[MAXN+10][MAXN+10];
void Read(int &x){
    char c;
    while(c=getchar(),c!=EOF)
        if(c>='0'&&c<='9'){
            x=c-'0';
            while(c=getchar(),c>='0'&&c<='9')
                x=x*10+c-'0';
            ungetc(c,stdin);
            return;
        }
}
void read(){
    Read(n),Read(k);
    int i;
    for(i=1;i<=n;i++)
        Read(r[i]);
}
void prepare(){
    int i,j;
    for(i=1;i<=n;i++){
        dist[i][1]=0;
        for(j=2;j<=n;j++)
            dist[i][j]=r[(i+j-2)%n+1]*(j-1)+dist[i][j-1];
    }
}
void dp(){
    int i,j,l,t=2*n,p;
    memset(f,0x3f,sizeof f);
    for(i=0;i<=t;i++)
        f[i][0][0]=0;
    for(i=1;i<=n;i++){
        for(j=1;j<=n&&j<=i;j++)
            for(l=1;l<=k;l++)
                for(p=1;p<=j;p++)
                    f[i][j][l]=min(f[i][j][l],f[i-p][j-p][l-1]+dist[i-p+1][p]);
        ans=min(ans,f[i][n][k]);
    }
    for(i=n+1;i<=t;i++){
        for(j=1;j<=n;j++)
            for(l=1;l<=k;l++)
                for(p=1;p<=j;p++)
                    f[i][j][l]=min(f[i][j][l],f[i-p][j-p][l-1]+dist[(i-p)%n+1][p]);
        ans=min(ans,f[i][n][k]);
    }
}
int main()
{
    read();
    prepare();
    dp();
    printf("%lld\n",ans);
}

你可能感兴趣的:(C++,dp,USACO,noip)