Description
Ink最近得到了一张藏宝图,这张图上共有n个藏宝室,但因为年代久远藏宝图上的路已经模糊不清,于是Ink找到了智慧的Pseudo,Pseudo告诉Ink,这个宝藏中每两个藏宝室之前都有一条通路,每条通路上都有一定数量的机关。现在Ink已经探明了其中n-1条路上的机关数目,这n-1条路不构成任何环路。众所周知Ink是个乐天派,他坚持认为自己探明的这些路构成的无环联通子图中机关总数是唯一且最少的,现在假设他的想法是对的,他想知道整个图中最少共有多少机关?
Input
第一行是一个数字n,表示藏宝室个数(0<n<=100)
第二行至第n行每行3个数u,v,w,表示探明的一条u到v的路,机关数是w.(1<=u,v<=n, 1<=w<=100).
Output
一个数,表示最少总机关数。
Sample Input
4 2 3 2 1 2 1 3 4 3
Sample Output
17
思路:给定最小生成树,求原来的图最少权值之和是多少。那么只要算加上一条边,加上之后必定成环,计算环上权值最大的边,那么加上去的这条边的权值就是环上最大权值+1,否则最少生成树会被破坏。
例如样例,
1---2---3---4 是这样的图。
加上1到3这条边,那么1,2,3成环,权值最大是2,那么1--3的权值就是2+1=3;
算好之后删除1--3这条边。
加上1--4,那么1,2,3,4成环,权值最大是3,那么1--4权值等于3+1=4;
删除1--4这条边。
加上2--4,那么2,3,4成环,权值最大是3,那么2--4权值等于3+1=4;
所有边的权值都算完了,ans=1+2+3+3+4+4=17;
用DFS可以判断哪些节点在环内。
#include<cstdio> #include<vector> #include<cstring> #include<algorithm> using namespace std; const int INF = 0x7FFFFFFF; const int maxn = 105; int jz[maxn][maxn]; vector<int> ljb[maxn]; int anss, flag; int cost[maxn]; int ff[maxn]; void dfs(int start,int end,int now,int tot) { int i; if (now == end) { int maxn = -1; flag = 1; for (i = 0; i < tot - 1; i++) { if (jz[cost[i]][cost[i + 1]]>maxn) maxn = jz[cost[i]][cost[i + 1]]; } anss = anss + maxn + 1; return; } for (i = 0; i < ljb[now].size(); i++) { if (ff[ljb[now][i]] == 0) { ff[ljb[now][i]] = 1; cost[tot] = ljb[now][i]; dfs(start, end, ljb[now][i], tot + 1); if (flag) return; } } } int main() { int n, i, j, u, v, c; while (~scanf("%d", &n)) { anss = 0; for (i = 0; i <= n; i++) for (j = 0; j <= n; j++) jz[i][j] = INF; for (i = 0; i <= n; i++) ljb[i].clear(); for (i = 1; i <= n - 1; i++) { scanf("%d%d%d", &u, &v, &c); jz[u][v] = c; jz[v][u] = c; anss = anss + c; ljb[u].push_back(v); ljb[v].push_back(u); } for (i = 1; i <= n; i++) { for (j = i + 1; j <= n; j++) { if (jz[i][j] == INF) { memset(ff, 0, sizeof(ff)); ff[i] = 1; cost[0] = i; flag = 0; dfs(i, j, i, 1); } } } printf("%d ", anss); } return 0; }