3836: [Poi2014]Tourism

来源:互联网 发布:梦幻西游数据号怎么弄 编辑:程序博客网 时间:2024/06/06 17:13

树形dp,多开一维记录祖先状态;
转移时其实是使用的泛化背包的转移方式,使程序简洁高效;

#include<bits/stdc++.h>#define rep(i,k,n) for(int i=k;i<=(n);i++)using namespace std;const int N=20005;const int M=100005;const int inf=0x3f3f3f3f;struct E{    int to,next;E(int to=0,int next=0):to(to),next(next){}}edge[M];int head[N],tot=0,C[N],bin[13];inline void mi(int &x,int y){    if(y<x)x=y;}void add(int x,int y){    edge[++tot]=E(y,head[x]);head[x]=tot;    edge[++tot]=E(x,head[y]);head[y]=tot;}int n,m,vis[N],f[12][60000],dep[N],stk[N],top;void dfs(int x){int d;    vis[x]=1;    int s=bin[dep[x]+1];    if(!(d=dep[x]))f[0][0]=C[x],f[0][1]=0,f[0][2]=inf;    else {    rep(i,0,s-1)f[d][i]=inf;    top=0;    for(int i=head[x];i;i=edge[i].next){        int v=edge[i].to;        if(vis[v]&&dep[v]<dep[x])stk[++top]=dep[v];    }        rep(i,0,bin[d]-1){            int ne=i,t=1;            rep(j,1,top){                int v=stk[j];                int op=(i/bin[v])%3;                if(op==1)ne=ne+bin[v];                else if(!op)t=2;            }            mi(f[d][i+t*bin[d]],f[d-1][i]);            mi(f[d][ne],f[d-1][i]+C[x]);        }    }    for(int i=head[x];i;i=edge[i].next){        int v=edge[i].to;        if(!vis[v]){            dep[v]=dep[x]+1,dfs(v);            rep(i,0,s-1)            f[d][i]=min(f[d+1][i],f[d+1][i+2*bin[d+1]]);        }    }}int main(){//  freopen("in.in","r",stdin);    bin[0]=1;rep(i,1,12)bin[i]=bin[i-1]*3;    scanf("%d%d",&n,&m);    rep(i,1,n)scanf("%d",&C[i]);    int x,y;    rep(i,1,m){        scanf("%d%d",&x,&y);        add(x,y);    }int ans=0;    rep(i,1,n){        if(!vis[i]){        dfs(i);        ans+=min(f[0][0],f[0][2]);       }    }    printf("%d\n",ans);}
0 0
原创粉丝点击