Problem from:http://acm.hdu.edu.cn/showproblem.php?pid=3274
从government选取的villages中任意选一个village作为树的根节点,在树上深搜
此题并不用把树生成出来,把每条边以两条边(双向)的方式存入图中
在图中进行深搜(每个节点只遍历一次)
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include<cstdio> #include<cstring> const int MAXN=1010; int head[MAXN],n,m,t,s,ans;//s在输入被选择的点的时候用,在开始深搜时,s存储的是最后一个被选择的点(作为树的根节点) bool cho[MAXN],vis[MAXN];//cho[]标记是否被选择,vis[]标记是否已遍历 struct Edge{ int to,next,w; }e[MAXN<<1]; void addedge(int u,int v,int c){ e[t].to=v; e[t].w=c; e[t].next=head[u]; head[u]=t++; } bool dfs(int rt){//返回以rt为根的树中是否含有被选择的点 vis[rt]=true; int k=head[rt]; bool flag=false;//标记以rt为根的子树中是否含有被选择的点 while(k>=0){ if(!vis[e[k].to] && dfs(e[k].to)){ flag=true; ans+=e[k].w; } k=e[k].next; } return (flag||cho[rt]); } void init(){ memset(cho,false,sizeof(cho)); memset(vis,false,sizeof(vis)); memset(head,-1,sizeof(head)); for(int i=0;i<m;i++){ scanf("%d",&s); cho[s]=true; } int u,v,c; t=0; for(int i=1;i<n;i++){ scanf("%d%d%d",&u,&v,&c); addedge(u,v,c); addedge(v,u,c); } } int main() { while(scanf("%d%d",&n,&m)!=EOF){ init(); ans=0; dfs(s); printf("%d\n",ans); } return 0; }