luogu 4042 有后效性的dp

存在有后效性的dp,但转移方程

f[i] = min( f[i], s[i] + sigma f[j] ( j 是后效点) ) 

每次建当前点和 转移点的边 e1, 某点和其会影响的点 e2 

spfa 利用以前的转移点更新答案,然后将所有受到其影响的点放入队列中再次更新

spfa 处理有后效性的dp

#include<bits/stdc++.h>
#define int long long
#define rep(i,x,y) for(register int i=x;i<=y;i++)

using namespace std;

const int N=2e5+50;
const int M=1e6+50;

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;}

int head1[N],tot1,head2[N],tot2,n,f[N],s[N];
struct node{int v,next;}e[M],e2[M];
inline void insert1(int u,int v){
    e[++tot1]=(node){v,head1[u]};head1[u]=tot1;}    
inline void insert2(int u,int v){
    e2[++tot2]=(node){v,head2[u]};head2[u]=tot2;}
    
bool vis[N];    
queue<int> q;    
    
inline void spfa(){
    rep(i,1,n) q.push(i),vis[i]=1;
    while(!q.empty()){
        int u=q.front();q.pop();vis[u]=0;
        
        int sum=0;
        for(int i=head1[u];i;i=e[i].next){
            int v=e[i].v;
            sum+=f[v];
        }
        sum+=s[u];
        if(sum<f[u]){
            f[u]=sum;
            for(int i=head2[u];i;i=e2[i].next){
                int v=e2[i].v;
                if(!vis[v]){
                    vis[v]=1;
                    q.push(v);
                }
            }
        }
    }
}    
    
#undef int
int main(){
#define int long long 
    n=read();
    rep(i,1,n){
        s[i]=read(),f[i]=read();int k=read();
        rep(j,1,k){
            int r=read();
            insert1(i,r);insert2(r,i);
        }
    }
    spfa();
    printf("%lld\n",f[1]);return 0;
}

 

posted @ 2018-10-10 21:14  ASDIC减除  阅读(392)  评论(0编辑  收藏  举报