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”,否则输出最小边权和。
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; }
相关文章推荐
- 最小树形图模板朱刘算法分享
- 初学ACM - 组合数学基础题目PKU 1833
- POJ ACM 1001
- POJ ACM 1002
- 1611:The Suspects
- POJ1089 区间合并
- POJ 2159 Ancient Cipher
- POJ 2635 The Embarrassed Cryptographe
- POJ 3292 Semi-prime H-numbers
- POJ 2773 HAPPY 2006
- POJ 3090 Visible Lattice Points
- POJ-2409-Let it Bead&&NYOJ-280-LK的项链
- POJ-1695-Magazine Delivery-dp
- POJ1523 SPF dfs
- POJ-1001 求高精度幂-大数乘法系列
- POJ-1003 Hangover
- POJ-1004 Financial Management
- POJ1050 最大子矩阵和
- 用单调栈解决最大连续矩形面积问题
- 2632 Crashing Robots的解决方法