zswx

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

//     最小树形图的朱刘算法
//     临接表实现
//     题目:poj3164
//     时间复杂度,据说是O(VE)
//     2011年9月15日
//
#include <iostream>
#include <cstdio>
#include <cmath>
#include <memory.h>
#define scale 110
#define eps 1e-8
using namespace std;

struct Node {
    int to;
    double value;
    bool flag;
    Node * next;
} array[scale*scale];
int amount;
Node * graph[scale];  //邻接表存有向图
struct cost_from {
    double cost;
    int from, circle_id;
} mini[scale];  //记录最小入边

void dfs(int * flag, int t) {
    flag[t] = 1;
    Node * p = graph[t];
    while (p != NULL) {
        if (!flag[p->to]) dfs(flag, p->to);
        if (p->to == t) p->flag = false;  //去掉自环
        p = p->next;
    }
}

double zhuliu(int n, int root) {
    int i, j, temp;
    int flag[scale], id[scale], new_id[scale];
    double sum;
    bool sign;
    Node * p;
    memset(flag, 0, sizeof(flag));
    dfs(flag, root);  //判断能否从跟到达所有节点
    for (i = 0; i < n; i++) {
        id[i] = i;
        if (!flag[i]) return -1;
    }
    if (true) sum = 0;
    while (true) {
        for (i = 0; i < n; i++) mini[i].from = -1;
        for (i = 0; i < n; i++) {
            p = graph[i];
            while (p != NULL) {
                if (p->flag && p->to != root) {
                    j = id[p->to];
                    if (mini[j].from == -1 || mini[j].cost > p->value) {
                        mini[j].cost = p->value;
                        mini[j].from = id[i];
                    }
                }
                p = p->next;
            }
        }
        sign = false;
        memset(flag, -1, sizeof(flag));
        memset(new_id, -1, sizeof(new_id));
        for (i = 0; i < n; i++) {
            if (mini[i].from != -1) {
                if (new_id[i] == -1) {
                    j = i;
                    do {
                        flag[j] = i;
                        j = mini[j].from;
                    } while (j != -1 && flag[j] == -1);
                    if (j != -1 && flag[j] == i) {  //构成环
                        sign = true;
                        temp = j;
                        do {
                            new_id[j] = temp;  //环中顶点被赋予相同的id
                            j = mini[j].from;
                        } while (j != temp);
                    }
                }
                sum += mini[i].cost;
            }
        }
        if (!sign) break;  //没有构成环就退出
        else {
            for (i = 0; i < n; i++) {
                p = graph[i];
                while (p != NULL) {
                    if (p->flag && p->to != root) {
                        j = new_id[id[p->to]];
                        p->value -= mini[id[p->to]].cost;  //到达除root外所有点的边的权值都要变化
                        if (j != -1 && j == new_id[id[i]]) p->flag = false;  //去掉产生的新的自环
                    }
                    p = p->next;
                }
            }
            for (i = 0; i < n; i++) {
                j = new_id[id[i]];
                if (j != -1) id[i] = j;  //每个点的id可能会产生变化
            }
        }
    }
    return sum;
}

void add(int a, int b, double dis) {
    if (fabs(dis) < eps) return ;
    array[amount].to = b;
    array[amount].value = dis;
    array[amount].flag = true;
    array[amount].next = graph[a];
    graph[a] = &array[amount++];
}

int main() {
    int n, m, i, s, e;
    int data[scale][2];
    double ans;
    while (scanf("%d %d", &n, &m) != EOF) {
        for (i = 0; i < n; i++) {
            scanf("%d %d", &data[i][0], &data[i][1]);
            graph[i] = NULL;
        }
        if (true) amount = 0;
        for (i = 0; i < m; i++) {
            scanf("%d %d", &s, &e);
            s--;
            e--;
            add(s, e, sqrt(0.0+(data[s][1]-data[e][1])*(data[s][1]-data[e][1])+(data[s][0]-data[e][0])*(data[s][0]-data[e][0])));
        }
        ans = zhuliu(n, 0);
        if (fabs(ans + 1) < eps) printf("poor snoopy\n");
        else printf("%.2f\n", ans);
    }
    return 0;
}

posted on 2011-09-17 00:51  zswx  阅读(340)  评论(0编辑  收藏  举报