题意:
输入n,表示有n个城市,分别为1~n,输入n-1组a,b,表示从a能走到b,求最少改变多少条路使得从其中的两个城市出发能走完所有的城市。
(http://blog.csdn.net/metalseed/article/details/8045038%20 与建树有关的东西 )
解题思路:
建立一棵树,断开一条边,把树分成两部分,计算这两部分的最小改变量
那么就变成了子树最小改变量的问题
dp[i]表示以i为根的子树需要的改变量
如果以root为起点,那么cost[root] = dp[root] 如果以这棵子树上的任意一个u为起点
则 cost[u] = dp[root] + u-root需要改变的量 - root-u需要改变的量
要使cost[u]最小,则(u-root需改变+root-u需改变)值最小
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 #include <cmath> 6 using namespace std; 7 const int N = 1e5 + 10; //1e5是10的5次方 8 struct Edge 9 { 10 int from, to, dis, nex; 11 }edge[N<<1]; 12 int head[N], edgenum; 13 void add(int u, int v, int d) 14 { 15 Edge E = { u, v, d, head[u] }; 16 edge[edgenum] = E; 17 head[u] = edgenum++; 18 } 19 int dp[N]; 20 int n, mx; 21 void dfs(int u, int fa, int val) 22 { 23 dp[u] = 0; 24 for (int i = head[u]; ~i; i = edge[i].nex)//~i表示取反,其实就是非零 25 { 26 int v = edge[i].to; 27 if (v == fa)continue; 28 dfs(v, u, val-edge[i].dis); 29 dp[u] += dp[v] + (edge[i].dis!=1);//如果括号里的成立则加1,否则加0 30 } 31 mx = max(mx, val); 32 } 33 int main() 34 { 35 while (cin >> n) 36 { 37 if (n == 1){ puts("0"); continue; }//puts 输出并换行 头文件cstdio 38 memset(head, -1, sizeof head); 39 edgenum = 0; 40 for (int i = 1, u, v; i < n; i++) 41 { 42 scanf("%d %d", &u, &v); 43 add(u, v, 1); 44 add(v, u, -1); 45 } 46 int ans = 1 << 30; 47 for (int i = 0, u, v; i < edgenum; i += 2) 48 { 49 u = edge[i].from; v = edge[i].to; 50 mx = -(1<<30); 51 dfs(u, v, 0); 52 int tmp = dp[u] - mx; 53 mx = -(1<<30); 54 dfs(v, u, 0); 55 tmp += dp[v] - mx; 56 ans = min(ans, tmp); 57 } 58 printf("%d\n", ans); 59 } 60 return 0; 61 }
时间: 2024-10-14 06:15:57