0
点赞
收藏
分享

微信扫一扫

【POJ 3164】Command Network(最小树形图)

1.​​题目链接​​​。最小树形图问题:最小树形图就是有向图的最小生成树,当然生成的是一颗有向树。具体可见:最小树形图。

2.这个题就是最小树形图的裸题了,偷了大佬的板子。




//#include<bits/stdc++.h>
#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<stdio.h>
#define INF 1e9
#define N 10001
#define LL long long
using namespace std;
struct Node
{
double x, y;
}node[N];
struct Edge {
int x, y;
double w;
}edge[N];
int vis[N];
int id[N];
int pre[N];
double in[N];
double zhuLiu(int root, int n, int m) {
double res = 0;
while (true) {

for (int i = 0; i < n; i++)
in[i] = INF;

for (int i = 0; i < m; i++) {
int x = edge[i].x;
int y = edge[i].y;
if (edge[i].w < in[y] && x != y) {
pre[y] = x;
in[y] = edge[i].w;
}
}
for (int i = 0; i < n; i++) {
if (i == root)
continue;
if (in[i] == INF)
return -1;
}

int cnt = 0;
in[root] = 0;
memset(id, -1, sizeof(id));
memset(vis, -1, sizeof(vis));
for (int i = 0; i < n; i++) {
res += in[i];

int y = i;
while (vis[y] != i && id[y] == -1 && y != root) {
vis[y] = i;
y = pre[y];
}

if (y != root && id[y] == -1) {
for (int x = pre[y]; x != y; x = pre[x])
id[x] = cnt;
id[y] = cnt++;
}
}
if (cnt == 0)
break;
for (int i = 0; i < n; i++)
if (id[i] == -1)
id[i] = cnt++;

for (int i = 0; i < m; i++) {
int x = edge[i].x;
int y = edge[i].y;
edge[i].x = id[x];
edge[i].y = id[y];

if (id[x] != id[y])
edge[i].w -= in[y];
}

n = cnt;
root = id[root];
}
return res;
}
double calculate(Node a, Node b) {
return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}
int main() {
int n, m;
while (scanf("%d%d", &n, &m) != EOF && (n + m))
{
for (int i = 0; i < n; i++)
scanf("%lf%lf", &node[i].x, &node[i].y);
for (int i = 0; i < m; i++) {
scanf("%d%d", &edge[i].x, &edge[i].y);
//点的编号是从[0,n-1]
edge[i].x--;
edge[i].y--;
if (edge[i].x != edge[i].y)
edge[i].w = calculate(node[edge[i].x], node[edge[i].y]);
else
edge[i].w = INF;//如果存在自环,就赋值为INF
}
double res = zhuLiu(0, n, m);//最小生成树的边权
if (res == -1)
printf("poor snoopy\n");
else
printf("%.2f\n", res);
}
return 0;
}

 


举报

相关推荐

0 条评论