题意:有n个地方需要供水,每个地方都可以选择是自己挖井,还是从别的地方引水,根据方法不同和每个地方的坐标不同,花费也不同,现在给出每个地方的坐标,花费的计算方法,以及每个地方可以给哪些地方供水(即对方可以从这里引水),求给所有地方供水的最小花费。
思路:建立一个源点,到每个点的距离为自己打井的费用,其他的按条件建边。根据poj3164改过来的。
#include <iostream> #include <vector> #include <map> #include <set> #include <deque> #include <queue> #include <stack> #include <cstdio> #include <cmath> #include <string> #include <cstring> #include <cmath> #define INF 2000000000 #define MAXN 1005 #define MAXM 1005 #define eps 1e-4 using namespace std; typedef int type; struct Point { int x,y,z; }p[MAXN*MAXN]; int X,Y,Z; struct node { int u, v; type w; }edge[MAXN * MAXN]; int E; int pre[MAXN], id[MAXN], vis[MAXN], n, m; type in[MAXN]; int dis(Point a, Point b) { return abs(a.x-b.x)+abs(a.y-b.y)+abs(a.z-b.z); } type Directed_MST(int root, int V, int E) { type ret = 0; while(true) { //1.找最小入边 for(int i = 0; i < V; i++) in[i] = INF; for(int i = 0; i < E; i++) { int u = edge[i].u; int v = edge[i].v; if(edge[i].w < in[v] && u != v) {pre[v] = u; in[v] = edge[i].w;} } for(int i = 0; i < V; i++) { if(i == root) continue; if(in[i] == INF) return -1;//除了根以外有点没有入边,则根无法到达它 } //2.找环 int cnt = 0; memset(id, -1, sizeof(id)); memset(vis, -1, sizeof(vis)); in[root] = 0; for(int i = 0; i < V; i++) //标记每个环 { ret += in[i]; int v = i; while(vis[v] != i && id[v] == -1 && v != root) //每个点寻找其前序点,要么最终寻找至根部,要么找到一个环 { vis[v] = i; v = pre[v]; } if(v != root && id[v] == -1)//缩点 { for(int u = pre[v]; u != v; u = pre[u]) id[u] = cnt; id[v] = cnt++; } } if(cnt == 0) break; //无环 则break for(int i = 0; i < V; i++) if(id[i] == -1) id[i] = cnt++; //3.建立新图 for(int i = 0; i < E; i++) { int u = edge[i].u; int v = edge[i].v; edge[i].u = id[u]; edge[i].v = id[v]; if(id[u] != id[v]) edge[i].w -= in[v]; } V = cnt; root = id[root]; } return ret; } int main() { while(scanf("%d%d%d%d", &n,&X,&Y,&Z)!= EOF) { if(!n&&!X&&!Y&&!Z)break; E=0; for(int i=1;i<=n;i++) { scanf("%d%d%d",&p[i].x,&p[i].y,&p[i].z); edge[E].u=0; edge[E].v=i; edge[E].w=p[i].z*X; E++; } for(int i=1;i<=n;i++) { int k,rel; scanf("%d",&k); while(k--) { scanf("%d",&rel); if(rel==i) { edge[E].u=i;edge[E].v=rel; edge[E].w=INF; } else { edge[E].u=i;edge[E].v=rel; if(p[i].z>=p[rel].z) edge[E].w=dis(p[i],p[rel])*Y; else edge[E].w=dis(p[i],p[rel])*Y+Z; E++; } } } int ans=Directed_MST(0,n+1,E); cout<<ans<<endl; } return 0; }