题意:有一个村庄需要修建供水系统。每户居民的房子都有一个三维坐标,每户居民可以选择自己挖井或者从其他居民家里引水。挖水井和引水分别需要花费不同的钱。每户居民有一个意愿表,只愿意对表内的居民家供水。最后要求计算出能为所有居民供水的最小花费。
题解:最小树形图+虚根
建一个虚根,将虚根连向所有点,边权为那个点自己挖井需要的费用。
其他按照居民意愿建边,跑朱刘。
数组开小了居然超时。
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<queue>
#include<stack>
#include<cmath>
#include<vector>
#include<fstream>
#include<set>
#include<map>
#include<sstream>
#include<iomanip>
#define ll long long
using namespace std;
const int INF = 0x3f3f3f3f;
const int MAXN = 1010;
const int MAXM = 1000010;
struct Edge {
int u, v;
int cost;
}edge[MAXM];
int pre[MAXN], id[MAXN], vis[MAXN];
int in[MAXN];
int zhuliu(int rt, int n, int m) {
int u, v;
int res = 0;
while (1) {
for (int i = 0; i < n; i++) in[i] = INF;
for (int i = 0; i < m; i++)
if (edge[i].u != edge[i].v && edge[i].cost < in[edge[i].v]) {
pre[edge[i].v] = edge[i].u;
in[edge[i].v] = edge[i].cost;
//if (edge[i].u == rt) pos = i; //虚根
}
for (int i = 0; i < n; i++)
if (i != rt && in[i] == INF) return -1;//不存在最小树形图
int tn = 0;
memset(id, -1, sizeof(id));
memset(vis, -1, sizeof(vis));
in[rt] = 0;
for (int i = 0; i < n; i++) {
res += in[i];
v = i;
while (vis[v] != i && id[v] == -1 && v != rt) {
vis[v] = i;
v = pre[v];
}
if (v != rt && id[v] == -1) {
for (int u = pre[v]; u != v; u = pre[u]) id[u] = tn;
id[v] = tn++;
}
}
if (tn == 0) break;//没有有向环
for (int i = 0; i < n; i++)
if (id[i] == -1) id[i] = tn++;
for (int i = 0; i < m; i++) {
v = edge[i].v;
edge[i].u = id[edge[i].u];
edge[i].v = id[edge[i].v];
if (edge[i].u != edge[i].v) edge[i].cost -= in[v];
}
n = tn;
rt = id[rt];
}
return res;
}
int n, x, y, z, a[MAXN], b[MAXN], c[MAXN];
int dis(int xa, int ya, int za, int xb, int yb, int zb) {
return (abs(xa - xb) + abs(ya - yb) + abs(za - zb)) * y + (za >= zb ? 0 : z);
}
int main() {
while (~scanf("%d%d%d%d", &n, &x, &y, &z) && n) {
for (int i = 0; i < n; i++) scanf("%d%d%d", &a[i], &b[i], &c[i]);
int L = 0;
for (int i = 0; i < n; i++) {
int k, temp;
scanf("%d", &k);
for (int j = 1; j <= k; j++) {
scanf("%d", &temp); temp--;
if (i == temp) continue;
edge[L].u = i;
edge[L].v = temp;
edge[L++].cost = dis(a[i], b[i], c[i], a[temp], b[temp], c[temp]);
}
}
for (int i = 0; i < n; i++) {
edge[L].u = n;
edge[L].v = i;
edge[L++].cost = x * c[i];
}
printf("%d\n", zhuliu(n, n + 1, L));
}
return 0;
}