CCPC - k题(dp)

来源:互联网 发布:网络嗅探器怎么用 编辑:程序博客网 时间:2024/05/08 21:13

本题目的意思:

给定n个位置,每个位置有一个二元组,要求确定n个位置的属性(选1或者是2),使得每个二元组的1属性和2属性去最近的位置,总代价最小(代价 属性值*移动距离)

分析:

可以尝试如此规划,定义d[ i ][ j ]为当前修到了i位置,i位置的属性为j,那么下面的一段连续路径要修的属性为(3-j),这一段路径上的属性为(3-j)的不需要移动,剩下的要移动到两边。

这个题目难得地方在于怎样设计状态使得具有很好的规划性质。

附: 交题点击打开链接

#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#define rep1(i,x,y) for(int i=x;i<=y;i++)#define rep(i,n) for(int i=0;i<(int)n;i++)using namespace std;typedef long long ll;const int inf = 0x3f3f3f3f;const int N = 4010;int n;struct node{    ll pre[N],pp[N],suf[N],ss[N];    void init()    {        pre[0]=pp[0]=suf[n+1]=ss[n+1]=0;        rep1(i,1,n) pre[i]=pre[i-1]+pre[i],pp[i]=pre[i]+pp[i-1];        for(int i=n; i>=1; i--) suf[i]=suf[i+1]+suf[i],ss[i]=ss[i+1]+suf[i];    }    ll get_lr(int i,int j)    {        int mid=(j-i-1)/2+i , llen = mid-i , rlen = j-mid-1;        ll sum = 0;        sum+=ss[i+1]-ss[mid+1]-suf[mid+1]*llen;        sum+=pp[j-1]-pp[mid]-pre[mid]*rlen;        return sum;    }    ll get(int i,int j)    {        if(i == 0) return pp[j-1];        else if(j == n+1) return ss[i+1];        return get_lr(i,j);    }} T,P;ll d[N][2];bool vis[N][2];ll dp(int i,int j){    if(vis[i][j]) return d[i][j];    vis[i][j] = true;    if(i == n) return d[i][j] = 0;    int lim = (i==0 ? n-1 : n);    rep1(k,i+1,lim)    {        ll add=(j==0 ? T.get(i,k+1):P.get(i,k+1));        if(k == i+1) d[i][j] = dp(k,j^1)+add;       else  d[i][j] = min(d[i][j],dp(k,j^1)+add);    }    return d[i][j];}int main(){    int Ta,kase=1;    scanf("%d",&Ta);    while(Ta--)    {        scanf("%d",&n);        int x,y;        rep1(i,1,n) scanf("%d %d",&x,&y),T.pre[i]=T.suf[i]=x,P.pre[i]=P.suf[i]=y;        T.init();        P.init();        memset(vis,false,sizeof(vis));        cout<<"Case #"<<kase++<<": "<<min(dp(0,0),dp(0,1))<<endl;    }    return 0;}



0 0
原创粉丝点击