wa2 图论
【问题描述】
山山最近开始玩一款叫做《白色相簿 2》的 Galgame。众所周知,Galgame 的剧情可以
用一棵树来表示,其中非叶节点表示选项分支,叶子表示结局,树边表示支线剧情,剧情从
树根开始向叶子方向进行。看完一段支线剧情所花的时间是一定的。
《白色相簿 2》共有 n 个选项分支或结局,有 n - 1 段支线剧情,其中根节点被编号
为 1 号。因为山山非常心急,于是他把自己的存档功能搞崩了。
山山现在只能在固定的 k 个选项前存档,每次观看剧情需要从存档处开始。他想花最少
的时间看一遍所有的剧情。 但是他现在有一个赛艇比赛要看,于是他希望你能帮他计算出
这个最少时间。
【输入格式】
输入文件名为 wa2.in。
第一行为两个正整数 n k。
接下来一行 k 个正整数 s 1 s 2 s 3 ...s k ,表示 k 个存档点,保证 1 号节点是一个
存档点。
接下来 n - 1 行,每行三个整数 u v t,表示节点 u 和 v 之间的那段支线剧情需要花费 t
的时间观看。
(保证 u 是 v 的前置剧情或选项)
【输出格式】
输出文件名为 wa2.out。
输出仅一行一个整数 ans 表示答案。
【样例输入与输出】
5 2
1 2
1 2 3
2 3 2
2 4 1
1 5 6
12
其实这题没什么难度,就是需要注意几个方面:
建双向边,dist值小心处理,叶节点的判断。
我们看了题应该可以知道如果可以保存的话,那该点之上的剧情就不需要重新计算了,
所以我们只要dfs一遍就可以得出答案。
代码:
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<algorithm> #define ll long long #define il inline #define db double using namespace std; il int gi() { int x=0,y=1; char ch=getchar(); while(ch<'0'||ch>'9') { if(ch=='-') y=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { x=x*10+ch-'0'; ch=getchar(); } return x*y; } int head[100045],cnt; struct edge { int next,to; ll lon; }e[200045]; il void add(int from,int to,ll lon) { e[++cnt].next=head[from]; e[cnt].to=to; e[cnt].lon=lon; head[from]=cnt; } bool vis[100045]; ll ans; bool p[100045]; int du[100045]; void dfs(int x,ll dist) { if(vis[x]) ans+=dist,dist=0; int r=head[x]; p[x]=1; while(r!=-1) { int now=e[r].to; if(!p[now]) dfs(now,dist+e[r].lon); r=e[r].next; } } int main() { freopen("wa2.in","r",stdin); freopen("wa2.out","w",stdout); memset(head,-1,sizeof(head)); int n=gi(),k=gi(); for(int i=1;i<=k;i++) vis[gi()]=1; int x,y; ll z; for(int i=1;i<n;i++) { x=gi(),y=gi(); scanf("%lld",&z); du[x]++; du[y]++; add(x,y,z); add(y,x,z); } for(int i=1;i<=n;i++) if(du[i]==1) vis[i]=1; dfs(1,0); printf("%lld\n",ans); return 0; }
PEACE