您的位置:首页 > 其它

POJ 3164 Command Network(最小树形图)

2016-05-19 23:10 393 查看
题目链接:

POJ 3164 Command Network

题意:

给出n个点[下标从1–n]的坐标和m条单向边[i,j]表示可以从i点建一条边到j,权值是两点距离,

求将这n个点连通的最小边权和。如果无法连通输出”poor snoopy”,否则输出最小边权和。

#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 = 110;
const int MAX_M = 10010;
const double INF = 1e20;
const double eps = 1e-8;

int n, m;
int NV, NE; //NV和NE分别是结点和边个数(结点下标从0--NV - 1,边下标从0-- NE - 1)
int ID[MAX_N], vis[MAX_N], pre[MAX_N]; //结点重新编号后的编号、寻找环时是否访问、结点的前驱结点
double  In[MAX_N]; //结点入度最小值

struct Point{
double x, y;

Point() {}
Point(double _x, double _y) : x(_x),y(_y) {}

double dis(const Point& rhs) const {
return hypot(x - rhs.x, y - rhs.y);
}
}point[MAX_N];

struct Edge{
int u, v;
double w;

Edge() {}
Edge(int _u, int _v, double _w) :u(_u), v(_v), w(_w) {}
}edge[MAX_M];

double Directed_MST(int root)
{
double res = 0, w;
int u, v;
while(1){
//1.找最小入边
for(int i = 0; i < NV; i++) In[i] = INF; //将所有结点的入度设为-1
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++){ //检查是否存在除root孤立点,若存在则不存在最小树形图
if(i == root) continue;
if(In[i] == INF) return -1; //i是孤立点
}
//2.找环
int cnt = 0; //记录所有结点重新标号后新结点数量
memset(vis, -1, sizeof(vis));
memset(ID, -1, sizeof(ID));
In[root] = 0; //将根节点入度重设为0
for(int i = 0; i < NV; i++){ //遍历所有结点找环
res += In[i]; //结果加上当前结点的最少入度
v = i;
while(vis[v] != i && ID[v] == -1 && v != root){ //将v所在有向环(或有向单链)上的所有结点收缩为i结点
vis[v] = i;
v = pre[v];
}
if(v != root && ID[v] == -1){ //只有有向环时重新标号
for(int u = pre[v]; u != v; u = pre[u]){ //将i所在有向环上所有结点收缩为结点cnt
ID[u] = cnt;
}
ID[v] = cnt++;
}
}
if(cnt == 0) break; //只剩下了root所在的有向环
for(int i = 0; i < NV; ++i){
if(ID[i] == -1) ID[i] = cnt++; //root所在有向环上结点或者其他有向环外接单链上点重新标号
}
//3.建新图
for(int i = 0; i < NE; i++){ //更新其他点到环上的距离
u = edge[i].u;
v = edge[i].v;
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()
{
while(~scanf("%d%d", &n ,&m)){
NV = n, NE = m;
for(int i = 1; i <= n; ++i){
scanf("%lf%lf", &point[i].x, &point[i].y);
}
for(int i = 0; i < m; ++i){
int u, v;
scanf("%d%d", &u, &v);
if( u != v) edge[i].w = point[u].dis(point[v]);
else edge[i].w = INF;
edge[i].u = u - 1, edge[i].v = v - 1; //保证结点下标从0--NV-1
}
double ans = Directed_MST(0);
if(fabs(ans + 1) <= eps) printf("poor snoopy\n");
else printf("%.2f\n", ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  最小树形图 POJ