兔
兔
时间限制: 1 Sec 内存限制: 128 MB题目描述
小粉兔用集训队的奖金买下了一片地。
这片地上有 n 个房子,有些房子之间有道路,有些房子之间则是杂草。
她可以花费一定的代价拆毁一条道路,或是啃光一片草使得两个房子间可以通行(大雾)。
她喜欢生成树,所以她要让所有道路形成一棵生成树。
求最小花费。
这片地上有 n 个房子,有些房子之间有道路,有些房子之间则是杂草。
她可以花费一定的代价拆毁一条道路,或是啃光一片草使得两个房子间可以通行(大雾)。
她喜欢生成树,所以她要让所有道路形成一棵生成树。
求最小花费。
输入
第一行一个数,n。
接下来 n 行,每行 n 个数,代表 ai,j。如果为正数,说明它们之间没有道路,需要 ai,j的花费来修建;如果为负数,说明它们之间有道路,需要 −ai,j的花费来拆毁。
接下来 n 行,每行 n 个数,代表 ai,j。如果为正数,说明它们之间没有道路,需要 ai,j的花费来修建;如果为负数,说明它们之间有道路,需要 −ai,j的花费来拆毁。
输出
一行一个数,代表最小花费。
样例输入
3
0 1 -3
1 0 5
-3 5 0
样例输出
1
提示
对于 100% 的数据,5≤n≤1000,1≤|ai,j(i≠j)|≤1000,保证所有 ai,i=0且 ai,j=aj,i 。
题解
一道最小生成树。拆边和建边分开算。建边:从小到大建边。拆边:从小到大拆,这条边如果加到最小生成树上,不需要花费任何费用,不在最小生成树上就要花费-aij拆掉。不是很难想,可能比较麻烦。
1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 using namespace std; 5 const int N = 1009; 6 struct Edge 7 { 8 int x, y, z; 9 bool operator < (const Edge&a) 10 const 11 { 12 return z < a.z; 13 } 14 }g[N*N], p[N*N]; 15 int n, m1, m2, ans, f[N], sum; 16 int find(int x) 17 { 18 if(x != f[x]) 19 f[x] = find(f[x]); 20 return f[x]; 21 } 22 int main() 23 { 24 scanf("%d", &n); 25 for(int i = 1; i <= n; i++) 26 for(int j = 1; j <= n; j++) 27 { 28 int d; 29 scanf("%d", &d); 30 if(j <= i) continue; 31 if(d > 0) 32 { 33 ++m1; 34 g[m1].x = i; 35 g[m1].y = j; 36 g[m1].z = d; 37 } 38 else 39 { 40 ++m2; 41 p[m2].x = i; 42 p[m2].y = j; 43 p[m2].z = d; 44 } 45 } 46 for(int i = 1; i <= n ;i++) f[i] = i; 47 sort(g+1, g+m1+1); 48 sort(p+1, p+m2+1); 49 for(int i = 1; i <= m2; i++) 50 { 51 int fx = find(p[i].x); 52 int fy = find(p[i].y); 53 if(f[fx] != f[fy]) 54 f[fy] = f[fx]; 55 else 56 ans -= p[i].z; 57 } 58 for(int i = 1; i <= m1; i++) 59 { 60 int fx = find(g[i].x); 61 int fy = find(g[i].y); 62 if(f[fx] != f[fy]) 63 { 64 ans += g[i].z; 65 f[fy] = f[fx]; 66 } 67 } 68 printf("%d\n", ans); 69 return 0; 70 }