题目
http://acm.hdu.edu.cn/showproblem.php?pid=4009
题意
给定n个点的三维坐标,以及根节点到每个点的单向权值,再给定n个节点间相互单向连接的成本,求最小树形图。
思路
直接根据题意建图然后跑最小树形图模板,网上有人说这个题必定有解我觉得说法是错的,因为有些时候两点之间未必可以链接。
过程
因为对模板不是很熟WA了很多发也DeBug了很久,发现是找完环之后忘了标记整个环,具体表现是80到83行之间的代码忘了写,所以一直在错。再就是发现定义虚根的先后次序不影响最后的结果,以及在网上寻找模板进行对比的时候发现了fill()
这个函数。
fill(a,b,c);
等价于
for(int i=0 ; i<b ; i++) a[i] = c;
代码
//
// main.cpp
// L
//
// Created by LucienShui on 2017/7/15.
// Copyright © 2017年 LucienShui. All rights reserved.
//
#include <iostream>
#include <algorithm>
#include <set>
#include <string>
#include <vector>
#include <queue>
#include <map>
#include <stack>
#include <iomanip>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cctype>
#define il inline
#define ll long long
#define memset(a,b) memset(a,b,sizeof(a))
using namespace std;
#define maxn 1007
struct {
int x, y, z;
}point[maxn];
struct {
int u, v;
ll w;
}edge[maxn*maxn];
ll in[maxn];
int pre[maxn], id[maxn], vis[maxn];
const int INF = 0x3f3f3f3f;
int dis(int a, int b) {
int x = abs(point[a].x - point[b].x), y = abs(point[a].y - point[b].y),
z = abs(point[a].z - point[b].z);
return x + y + z;
}
ll directed_MST(int root, int n, int m) {
ll ans = 0;
while(true) {
fill(in, in+n, INF);//for(int i=0 ; i<n ; i++) in[i] = INF;
for(int i=0 ; i<m ; i++) {
int u = edge[i].u, v = edge[i].v;
if(edge[i].w < in[v] && u!=v) {
in[v] = edge[i].w;
pre[v] = u;
}
}
for(int i=0 ; i<n ; i++)
if(in[i] == INF && i != root)
return -1;
int cnt = 0;
memset(id, -1);
memset(vis, -1);
in[root] = 0;
for(int i=0 ; i<n ; i++) {
ans += 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;
/*line 80*/
for(int i=0 ; i<n ; i++)
if(id[i] == -1) id[i] = cnt++;
/*line 83*/
for(int i=0 ; i<m ; i++) {
int u = edge[i].u, v = edge[i].v;
edge[i].u = id[u];
edge[i].v = id[v];
if(id[u] != id[v]) {
edge[i].w -= in[v];
}
}
n = cnt;
root = id[root];
}
return ans;
}
int main (int argc, char* argv[]) {
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
#endif
int n, m, tmp, v, X, Y, Z;
while(scanf("%d%d%d%d", &n, &X, &Y, &Z), (n || X || Y || Z)) {
m = 0;
for(int i=1 ; i<=n ; i++) {
scanf("%d%d%d", &point[i].x, &point[i].y, &point[i].z);
edge[m].u = 0;
edge[m].v = i;
edge[m++].w = X * point[i].z;
}
for(int u=1 ; u<=n ; u++) {
scanf("%d",&tmp);
while(tmp--) {
scanf("%d",&v);
if(u == v) continue;
edge[m].u = u;
edge[m].v = v;
edge[m].w = Y * dis(u,v);
if(point[u].z < point[v].z) {
edge[m].w += Z;
}
m++;
}
}
ll ans = directed_MST(0,n+1,m);
if(ans == -1) puts("poor XiaoA");
else printf("%lld\n",ans);
}
return 0;
}