题目链接:Problem 1963 交通建设
思路:多建一个虚拟的点,如果有机场,就和这个点相连,然后就是最小生成树问题了,最后要注意如果一开始没有机场,并且最后只有一条边和虚拟点相连,是需要扣掉权值CA的。
代码:
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
const int N = 1005;
const int M = 12005;
__int64 n, m, ca, cb, p, q, ans, pi, qi, parent[N], i, vis[N], flag;
struct Edge {
__int64 u, v, value;
void scan() {
scanf("%I64d%I64d%I64d", &u, &v, &value);
value *= cb;
}
Edge() {}
Edge(__int64 _u, __int64 _v, __int64 _value) {
u = _u; v = _v; value = _value;
}
} e[M];
__int64 find(__int64 x) {
if (x == parent[x])
return x;
else return parent[x] = find(parent[x]);
}
bool Union(__int64 u, __int64 v) {
int pa = find(u);
int pb = find(v);
if (pa != pb) {
vis[u]++;
vis[v]++;
parent[pa] = pb;
return true;
}
return false;
}
bool cmp(Edge a, Edge b) {
return a.value < b.value;
}
__int64 solve() {
sort(e, e + m + n + 1, cmp);
for (i = 1; i <= m + n; i++) {
if (Union(e[i].u, e[i].v))
ans += e[i].value;
}
if (vis[n + 1] == 1 && !flag)
ans -= ca;
return ans;
}
int main() {
while (~scanf("%I64d%I64d%I64d%I64d", &n, &m, &ca, &cb)) {
memset(vis, 0, sizeof(vis));
ans = 0; flag = 0;
for (i = 1; i <= n + 1; i++)
parent[i] = i;
for (i = 1; i <= m; i++)
e[i].scan();
for (i = m + 1; i <= m + n; i++)
e[i] = Edge(i - m, n + 1, ca);
scanf("%I64d", &p);
ans += p * ca;
while (p--) {
flag = 1;
scanf("%I64d", &pi);
Union(pi, n + 1);
}
scanf("%I64d", &q);
while (q--) {
scanf("%I64d", &qi);
ans += e[qi].value;
Union(e[qi].u, e[qi].v);
}
printf("%I64d\n", solve());
}
return 0;
}