您的位置:首页 > 其它

poj_3164 Command Network(最小树形图+朱刘算法)

2017-02-07 20:31 537 查看
Command Network
Time Limit: 1000MS Memory Limit: 131072K
Total Submissions: 17372 Accepted: 5001
DescriptionAfter a long lasting war on words, a war on arms finally breaks out between littleken’s and KnuthOcean’s kingdoms. A sudden and violent assault by KnuthOcean’s force has rendered a total failure of littleken’s command network. A provisional network mustbe built immediately. littleken orders snoopy to take charge of the project.With the situation studied to every detail, snoopy believes that the most urgent point is to enable littenken’s commands to reach every disconnected node in the destroyed network and decides on a plan to build a unidirectional communication network. Thenodes are distributed on a plane. If littleken’s commands are to be able to be delivered directly from a node A to another node B, a wire will have to be built along the straight line segment connecting the two nodes. Since it’s in wartime, not between allpairs of nodes can wires be built. snoopy wants the plan to require the shortest total length of wires so that the construction can be done very soon.InputThe input contains several test cases. Each test case starts with a line containing two integerN (N ≤ 100), the number of nodes in the destroyed network, andM (M ≤ 104), the number of pairs of nodes between which a wire can be built. The nextN lines each contain an ordered pair xi and yi, giving the Cartesian coordinates of the nodes. Then followM lines each containing two integers i and j between 1 andN (inclusive) meaning a wire can be built between node i and nodej for unidirectional command delivery from the former to the latter. littleken’s headquarter is always located at node 1. Process to end of file.OutputFor each test case, output exactly one line containing the shortest total length of wires to two digits past the decimal point. In the cases that such a network does not exist, just output ‘
poor snoopy
’.Sample Input
4 6
0 6
4 6
0 0
7 20
1 2
1 3
2 3
3 4
3 1
3 2
4 3
0 0
1 0
0 1
1 2
1 3
4 1
2 3
Sample Output
31.19
poor snoopy
求最小有向生成树,也叫最小树形图:除根结点外,其他结点的入度都为1,从根结点可以到达其他所有结点。
最小树形图可以用朱刘算法解:
(1)先删除图G中的自环,它们显然不在最小树形图中。
(2)接下来给所有非根结点各选择一条权最小的入边,得到图G2,如果有非根结点没有找到入边,
则说明根结点无法到达该非根结点,即无解。
(3)图G2中如果没有圈,则说明G2就是最小树形图了;如果有圈,则进行缩圈处理后,重新构图,
然后重复上述过程。不过在缩圈之后再构图时,可能会有某个原始结点的入度为2,此时需要把该结点之前一条
入边删除,这等价于把新入边的权值减去之前那条入边的权值。
#include <iostream>#include <cstdio>#include <cstdlib>#include <cstring>#include <cmath>#include <stack>#include <bitset>#include <queue>#include <set>#include <map>#include <string>#include <algorithm>#define FOP freopen("data.txt","r",stdin)#define FOP2 freopen("data1.txt","w",stdout)#define inf 0x3f3f3f3f#define maxn 110#define mod 1000000007#define PI acos(-1.0)#define LL long longusing namespace std;struct Point{double x, y;};double dis(Point a, Point b){return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));}struct Edge{int from, to;double dist;Edge(int u = 0, int v = 0, double c = 0) : from(u), to(v), dist(c) {}};int n, m;Point p[maxn];Edge edges[maxn*maxn];int pre[maxn], id[maxn], vis[maxn]; //用于找圈和缩圈double in[maxn]; //in[i]表示顶点i的最小入边的权double Directed_MST(int root, int V, int E){double res = 0;int u, v;while(1){//找最小入边for(int i = 1; i <= V; i++) in[i] = inf;for(int i = 1; i <= E; i++){u = edges[i].from, v = edges[i].to;if(in[v] > edges[i].dist && u != v) in[v] = edges[i].dist, pre[v] = u;}for(int i = 1; i <= V; i++){if(i == root) continue;if(in[i] == inf) return -1; //除根节点外还有没有入边的节点,根节点无法到达它,无解}in[root] = 0;//找圈并缩圈int cot = 0;memset(id, -1, sizeof(id));memset(vis, -1, sizeof(vis));for(int i = 1; i <= V; i++){res += in[i];v = i;while(vis[v] != i && v != root && id[v] == -1) //找圈{vis[v] = i;v = pre[v];}if(v != root && id[v] == -1) //缩圈{id[v] = ++cot;for(u = pre[v]; u != v; u = pre[u]) id[u] = cot;}}if(cot == 0) break; //无圈,得解for(int i = 1; i <= V; i++)if(id[i] == -1) id[i] = ++cot;//重新构图for(int i = 1; i <= E; i++){u = edges[i].from, v = edges[i].to;edges[i].from = id[u], edges[i].to = id[v];if(id[u] != id[v]) edges[i].dist -= in[v];}V = cot;root = id[root];}return res;}int main(){while(~scanf("%d%d", &n, &m)){for(int i = 1; i <= n; i++) scanf("%lf%lf", &p[i].x, &p[i].y);int u, v;for(int i = 1; i <= m; i++){scanf("%d%d", &u, &v);edges[i] = Edge(u, v, dis(p[u], p[v]));if(u == v) edges[i].dist = inf; //去自环}double ans = Directed_MST(1, n, m);if(ans == -1) printf("poor snoopy\n");else printf("%.2f\n", ans);}return 0;}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: