[来源未知][树形dp]逐个击破

来源:互联网 发布:网络摄像机 要多少电压 编辑:程序博客网 时间:2024/06/06 04:56

内存128M,时限1s
逐个击破
【问题描述】
现在有N个城市,其中K个被敌方军团占领了,N个城市间有N-1条公路相连,破坏其中某条公路的代价是已知的,现在,告诉你K个敌方军团所在的城市,以及所有公路破坏的代价,请你算出花费最少的代价将这K个地方军团互相隔离开,以便第二步逐个击破敌人。
【输入格式】
第一行包含两个正整数n和k。
第二行包含k个整数,表示哪个城市别敌军占领。
接下来n-1行,每行包含三个正整数a,b,c,表示从a城市到b城市有一条公路,以及破坏的代价c。
城市的编号从0开始计数。
其中:2<=n<=100000,2<=k<=n,1<=c<=1000000。
【输出格式】
包含一个整数,表示最少花费的代价。
【输入输出样例一】
attack.in attack.out
3 3
0 1 2
0 1 1
1 2 2 3
【输入输出样例二】
attack.in attack.out
5 3
1 2 4
1 0 4
1 3 8
2 1 1
2 4 3 4
【数据范围与约定】
对于30%的数据:n <= 1000。
对于100%的数据:n <= 100000。

f[x][0]:
在x子树中敌军无法联系时花费的最小代价且最上方的点的路径未被切断

f[x][1]:
在x子树中敌军无法联系时花费的最小代价且最上方的点的路径已被切断(辅助记录路径最小值)

相当于对于一个点子树下有size个军事要塞,其中至少size-1个军事要塞被切断(剩下的那个军事要塞可能会在上面的路径被剪断,即可能取到更优值)
如果这个点也是军事要塞,则要切断size个。
就是取出size(-1)个已被切断的军事要塞和1(0)个未被切断的

#include<cstdio>#include<algorithm>#include<string>#include<cstring>#include<cstdlib>#include<cmath>#include<iostream>using namespace std;typedef long long ll;const int N=110000;const int M=210000;int n,m;inline int read(){    char c;    int res,flag=0;    while((c=getchar())>'9'||c<'0') if(c=='-')flag=1;    res=c-'0';    while((c=getchar())>='0'&&c<='9') res=(res<<3)+(res<<1)+c-'0';    return flag?-res:res;}int tot;int nex[M],go[M],fir[N],val[M],fval[N];int p[N],q[N],top;ll f[N][2],prev[N],nexv[N];bool stone[N];void dfs(int u,int fa){    if(go[fir[u]]==fa&&!nex[fir[u]])    {        f[u][1]=f[u][0]=0;        if(stone[u]) f[u][1]=fval[u];        return;    }    int e,v;    for(e=fir[u];v=go[e],e;e=nex[e])    if(v!=fa)    {        fval[v]=val[e];        dfs(v,u);    }    top=0;    for(e=fir[u];v=go[e],e;e=nex[e])    if(v!=fa)    {        ++top;        q[top]=f[v][1];        p[top]=f[v][0];        prev[top]=prev[top-1]+f[v][1];    }    nexv[top+1]=0;    for(int i=top;i>=1;--i)        nexv[i]=nexv[i+1]+q[i];    if(stone[u])    {        f[u][1]=prev[top]+fval[u];        f[u][0]=prev[top];    }    else    {        f[u][1]=prev[top];        for(int i=1;i<=top;++i)        {            f[u][0]=min(f[u][0],p[i]+prev[i-1]+nexv[i+1]);            f[u][1]=min(f[u][1],p[i]+prev[i-1]+nexv[i+1]+fval[u]);        }    }}inline void add(int x,int y,int z){    nex[++tot]=fir[x];fir[x]=tot;go[tot]=y;val[tot]=z;    nex[++tot]=fir[y];fir[y]=tot;go[tot]=x;val[tot]=z;}int main(){    freopen("attack.in","r",stdin);    freopen("attack.out","w",stdout);    n=read();    m=read();    for(int i=1;i<=m;++i) stone[read()]=1;    int x,y,z;    for(int i=2;i<=n;++i)    {        x=read();        y=read();        z=read();        add(x,y,z);        f[i][1]=f[i][0]=1e9;    }    f[1][1]=f[1][0]=f[0][0]=f[0][1]=1e9;    dfs(0,0);    printf("%lld",min(f[0][0],f[0][1]));}
原创粉丝点击