题目链接:
HDU 4009 Transfer water
题意:
需要给n户人家通水。给出每户人家的三维坐标,每户人家自建一口井的花费是X,对于每户人家给出k[i]条边,to[j],表示可以从第u=i户人家铺设一条水管道到第v=to[j]户人家,铺设的费用是两户人家三维坐标之差的绝对值之和*Y,如果u的高度小于v的高度还需要额外加上Z花费。问将n户人家都通上水的最小花费是多少?如果不能使每户人家都通上水就输出-1.
分析:
实际上不会输出-1的,因为每户人家都可以自建一口井。。。
每户人家之间的建边就按照题目叙述的那样建立边权就好了,主要是每户人家可以自建一口井花费X如何用边和边权表示?
可以新设一个根节点为0,从0到每户人家建立一条权值为X的边表示自建水井,这样子跑一下最小树形图就好了。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <climits>
#include <cmath>
#include <ctime>
#include <cassert>
#define IOS ios_base::sync_with_stdio(0); cin.tie(0);
using namespace std;
typedef long long ll;
const int MAX_N = 2010;
const int MAX_M = 1001000;
const int INF = 0x7fffffff;int n, X, Y, Z, K, NV, NE;
int vis[MAX_N], pre[MAX_N], ID[MAX_N];
ll In[MAX_N];struct Edge{int u, v;ll w;Edge() {}Edge(int _u, int _v, ll _w) : u(_u), v(_v), w(_w) { }
}edge[MAX_M];struct Point{int x, y, z;Point() {}Point(int _x, int _y, int _z) :x(_x), y(_y), z(_z) {}int dis(const Point& rhs) const {return abs(x - rhs.x) + abs(y - rhs.y) + abs(z - rhs.z);}
}point[MAX_N];ll ZLEdmonds(int root, int NV, int NE)
{ll res = 0, w;int u, v;while(1){for(int i = 0; i < NV; i++){In[i] = INF;}for(int i = 0; i < NE; i++){u = edge[i].u, v = edge[i].v, w = edge[i].w;if(u != v && w < In[v]){In[v] = w;pre[v] = u;}}for(int i = 0; i < NV; i++){if(i != root && In[i] == INF) return -1;}int cnt = 0;memset(vis, -1, sizeof(vis));memset(ID, -1, sizeof(ID));In[root] = 0;for(int i = 0; i < NV; i++){res += In[i];v = i;while(v != root && ID[v] == -1 && vis[v] != i){vis[v] = i;v = pre[v];}if(v != root && ID[v] == -1){for(u = pre[v]; u != v; u = pre[u]){ID[u] = cnt;}ID[v] = cnt ++;}}if(cnt == 0) break;for(int i = 0; i < NV; i++){if(ID[i] == -1) ID[i] = cnt++;}for(int i = 0; i < NE; i++){v = edge[i].v, u = edge[i].u;edge[i].u = ID[u], edge[i].v = ID[v];if(edge[i].u != edge[i].v){edge[i].w -= In[v];}}NV = cnt;root = ID[root];}return res;
}int main()
{IOS;while(~scanf("%d%d%d%d", &n, &X, &Y,&Z) && (n || X || Y || Z)){NE = 0;for(int i = 1; i <= n; i++){scanf("%d%d%d", &point[i].x, &point[i].y, &point[i].z);}for(int i = 1; i <= n; i++){scanf("%d", &K);int u = i;for(int j = 0; j < K; j++){int v;scanf("%d", &v);if(u == v) continue;ll w = point[u].dis(point[v]) * Y;if(point[u].z < point[v].z) w += Z;edge[NE++] = Edge(u, v, w);}}int root = 0;for(int i = 1; i <= n; i++){edge[NE++] = Edge(root, i, point[i].z * X);}NV = n + 1;ll ans = ZLEdmonds(root, NV, NE);if(ans == -1) printf("poor XiaoA\n");else printf("%lld\n", ans);}return 0;
}