[來源未知][樹形dp]逐個擊破


內存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]));
}


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2020 ITdaan.com