hdu 4313 Matrix
http://acm.hdu.edu.cn/showproblem.php?pid=4313
思路:有点贪心吧。先设a为b、c的father,分以下三种情况考虑:
1、如果a有机器人,b或c也有机器人,则一定要把a和b,c断开。
2、如果a、c没有机器人,且b有机器人,设d有机器人,且d为a的father,则问题可以转化成a有机器人,取b到d路径上的最小值。
3、如果a没有机器人,且b、c有机器人,则如果a到b的路径大于a到c的路径,则把b的机器人放到a点上,a到c的路径权值加到ans,反之~~~~。
这样每次都让叶子结点开始向上归约。每个结点都会进一次队,最后的时间复杂度为O(n).

#include<stdio.h> #include<string.h> #define maxn 100005 struct nd{ int v,next,c; }edge[200005]; int flag[maxn],vis[maxn],in[maxn],head[maxn],ecnt,as[maxn],que[maxn]; int Min(int x,int y){return x>y?y:x;} void add(int u,int v,int w) { edge[ecnt].v = v; edge[ecnt].c = w; edge[ecnt].next = head[u]; head[u] = ecnt++; } int main() { int a,b,c,i,n,k,t,ts,te; int inf = 1<<30; long long ans; scanf("%d",&t); while(t--){ scanf("%d %d",&n,&k); memset(flag,0,sizeof(flag)); memset(vis,0,sizeof(vis)); memset(in,0,sizeof(in)); memset(as,0,sizeof(as)); memset(head,-1,sizeof(head)); ecnt = 0; for(i = 0; i < n - 1; ++ i){ scanf("%d %d %d",&a,&b,&c); add(a,b,c); add(b,a,c); in[a]++; in[b]++; } for(i = 0; i < k; ++ i){ scanf("%d",&c); flag[c]=1; } te = ts = 0; for(i = 0; i < n; ++ i) if(in[i]==1){ if(flag[i]) as[i]=inf; que[te++]=i; } ans = 0; while(ts^te){ a = que[ts++]; vis[a] = 1; for(i = head[a]; i != -1; i = edge[i].next){ b = edge[i].v; c = edge[i].c; if(vis[b])continue; as[a] = Min(c,as[a]);//取路径上的最小值 in[b]--; if(in[b]==1){ if(flag[b]) as[b] = inf; que[te++] = b; } if(flag[b]){//第1种情况 ans += as[a]; }else if(as[a]){//第3种情况 if(as[b]>as[a]) ans += as[a]; else{ ans += as[b]; as[b] = as[a]; } } } } printf("%I64d\n",ans); } return 0; }