bzoj 4244 括号序列dp

将各种情况绕环等看作括号序列,括号内的区域上下都需要累加答案,左右也是

f[i][j] 代表 前i个车站已经处理完的有j个左括号的最小权值

我们可以发现,更新的来源来自于 i-1, 和 i

将上 描述为L1,L2, 下描述为R1,R2,所以可以通过括号内的沿伸以及左右括号的答案更新状态

具体代码如下

#include<bits/stdc++.h>
#define rep(i,x,y) for(register int i=x;i<=y;i++)
#define dec(i,x,y) for(register int i=x;i>=y;i--)
using namespace std;
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    return x*f;}
    
namespace zkc{
    const int N=3050;
    int n,T,L1[N],L2[N],R1[N],R2[N],f[N][N];
    
    inline void work(){
        n=read(),T=read();
        rep(i,1,n) R1[i]=read(),L1[i]=read(),L2[i]=read(),R2[i]=read();
        
        memset(f,0x3f,sizeof f);f[0][0]=0;
        rep(i,1,n){
            //from i-1 zhuan'yi
            rep(j,0,n){
                if(j){//来自于i-1的转移
                f[i][j]=min(f[i][j],f[i-1][j-1]+(j-1)*2*T+L1[i]+L2[i]);
                //第一个转移需要保证j的原因是其由左边j-1转移而来(
f[i][j]
=min(f[i][j],f[i-1][j]+j*2*T+L2[i]+R2[i]);}
//由于此条转移走的是下路,也就是已经到了下班状态,至少有一次向下的左括号还没有被匹配 //下班路上取邮戳
f[i][j]
=min(f[i][j],f[i-1][j]+j*2*T+L1[i]+R1[i]);
//上班路上取邮戳 f[i][j]
=min(f[i][j],f[i-1][j+1]+(j+1)*2*T+R1[i]+R2[i]); //匹配右括号
}
//前四种转移是强行为了更新状态而走邮戳站的,底下的两种是为了更新自己此节点的反复转移的情况,即在同一节点处多次更新 rep(j,
1,n) f[i][j]=min(f[i][j],f[i][j-1]+L1[i]+L2[i]); //先更新小的j-1再更新大的j+1
dec(j,n
-1,0) f[i][j]=min(f[i][j],f[i][j+1]+R1[i]+R2[i]);
} printf(
"%d\n",f[n][0]+(n+1)*T);return; } } int main(){ zkc::work(); return 0; }

完结撒花

不过话说回来,其实还有许多不太明白的转移顺序问题,日后慢慢理解哈

posted @ 2018-10-22 17:30  ASDIC减除  阅读(230)  评论(0编辑  收藏  举报