題目鏈接:點擊打開鏈接
解題思路:
根據相互之間的關係,可以轉化一個無向圖中最大權森林的問題。也就是把邊權取反,然後用最小生成樹求解。
本題用鄰接表存儲,Kruskal求最小生成樹。
完整代碼:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <set>
#include <vector>
#include <climits>
#include <queue>
using namespace std;
typedef long long LL;
const int maxn = 500001;
struct edge
{
int u , v , cost;
};
int n , m , r;
int x[maxn] , y[maxn] , d[maxn];
bool cmp(const edge &e1 , const edge &e2)
{
return e1.cost < e2.cost;
}
edge es[maxn];
int V , E;
int f[maxn] , rank[maxn];
void init_union_find(int cnt)
{
for(int i = 0 ; i <= cnt ; i ++)
{
f[i] = i;
rank[i] = 0;
}
}
int find(int key)
{
return f[key] = f[key] == key ? key : find(f[key]);
}
void unite(int x , int y)
{
x = find(x);
y = find(y);
if(x != y)
{
if(rank[x] < rank[y])
{
f[x] = y;
}
else
{
f[y] = x;
if(rank[x] == rank[y])
rank[x] ++;
}
}
}
bool same(int x , int y)
{
return find(x) == find(y);
}
int kruskal()
{
sort(es , es + E , cmp);
init_union_find(V);
int res = 0;
for(int i = 0 ; i < E ; i ++)
{
edge e = es[i];
if(!same(e.u , e.v))
{
unite(e.u , e.v);
res += e.cost;
}
}
return res;
}
void solve()
{
V = n + m;
E = r;
for(int i = 0 ; i < r ; i ++)
{
es[i] = (edge){ x[i] , n + y[i] , -d[i] };
}
LL res = 10000 * (n + m) + kruskal();
printf("%lld\n" , res);
}
int main()
{
#ifdef DoubleQ
freopen("in.txt" , "r" , stdin);
#endif
int T;
cin >> T;
while(T--)
{
//cin >> n >> m >> r;
scanf("%d%d%d" , &n , &m , &r);
for(int i = 0 ; i < r ; i ++)
{
//cin >> x[i] >> y[i] >> d[i];
scanf("%d%d%d" , &x[i] , &y[i] , &d[i]);
}
solve();
}
return 0;
}
更多精彩請訪問:點擊打開鏈接