HDU 4009 Transfer water (最小树形图+虚根)

题意:有一个村庄需要修建供水系统。每户居民的房子都有一个三维坐标,每户居民可以选择自己挖井或者从其他居民家里引水。挖水井和引水分别需要花费不同的钱。每户居民有一个意愿表,只愿意对表内的居民家供水。最后要求计算出能为所有居民供水的最小花费。

题解:最小树形图+虚根
建一个虚根,将虚根连向所有点,边权为那个点自己挖井需要的费用。

其他按照居民意愿建边,跑朱刘。

数组开小了居然超时。

#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;
}

猜你喜欢

转载自blog.csdn.net/qq_43680965/article/details/107826584
今日推荐