[来源未知][树形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]));}
- [来源未知][树形dp]逐个击破
- [来源未知][Dp]permut
- 洛谷 2700 逐个击破
- luogu 2700 逐个击破
- IT项目十大灾难逐个击破
- CSharp难点逐个击破文档分享
- 2017.9.2总结1-逐个击破
- [练习][洛谷2700]Kruskal 逐个击破
- newssoj1004逐个击破attack(排序+并查集)
- C#难点逐个击破(1):ref参数传递
- C#难点逐个击破2out返回参数
- C#难点逐个击破3params数组参数
- JZOJ2936. 【NOIP2012模拟8.9】逐个击破(2017.9B组)
- android开启未知来源
- [来源未知]卡片游戏
- [来源未知]传送
- [来源未知]虚
- [来源未知]阶乘和
- API学习Arrays
- 按位运算
- JQuerry简介
- JAVA迭代器与ArrayList集合的使用
- c++笔记2-操作符重载
- [来源未知][树形dp]逐个击破
- API学习Collection
- 一些密码学中的概念收集
- OSG动画库Animation解析(二)
- JS学习第二天
- 2017 Multi-University Training Contest
- 20170725 用Jquery修改CSS
- 自举电路、自举电容
- Uart串口实验