(有向图最小生成树)Command Network

http://poj.org/problem?id=3164

给出有向图下的点位置和单向边,求出图的最小生成树
不能用无向图算法,应该为朱-刘算法
算法步骤如下:
1.判断图的连通性,若不连通直接无解,否则一定有解。
2.为除了根节点以外的所有点选择一个权值最小的入边,假设用pre数组记录前驱,f数组记录选择的边长,记所选边权和为temp。
3.(可利用并查集)判断选择的的边是否构成环,若没有则直接ans+=temp并输出ans,若有,则进行下一步操作。
4.对该环实施缩点操作,设该环上有点V1,V2……Vi……Vn,缩成的点为node ,对于所有不在环中的点P进行如下更改:
(1) 点P到node的距离为min{a[p,Vi]-f[Vi]} (a为边集数组)
(2)点node到p的距离为min{a[Vi,p]}

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;

const int maxn = 103;
const double inf = 1e100;
int n, m, vis[maxn], pre[maxn], inc[maxn];
double x[maxn], y[maxn], w[maxn][maxn];
double getdis(int u, int v) {
    return sqrt((x[u] - x[v]) * (x[u] - x[v]) + (y[u] - y[v]) * (y[u] - y[v]));
}
void dfs(int u) {
    vis[u] = 1;
    for(int i = 1; i <= n; i++) if(w[u][i] != inf && !vis[i]) 
        dfs(i);
}
int main()
{

    while(~scanf("%d%d", &n, &m)) {
        for(int i = 1; i <= n; i++) scanf("%lf%lf", &x[i], &y[i]);

        for(int i = 1; i <= n; ++i) 
            for(int j = i; j <= n; ++j) 
                w[i][j] = w[j][i] = inf;
        memset(vis, 0, sizeof(vis));

        for(int i = 0; i < m; i++) {
            int u, v;
            scanf("%d%d", &u, &v);
            w[u][v] = min(w[u][v], getdis(u, v));
        }

        dfs(1);
        bool flg = true;
        for(int i = 1; i <= n; i++) if(!vis[i]) flg = false;
        if(!flg) {
            puts("poor snoopy");
            continue;
        }

        double ans = 0;
        memset(vis, 0, sizeof(vis));
        memset(inc, 0, sizeof(inc));
        while(true) {
            for(int i = 2; i <= n; i++) if(!inc[i]){
                w[i][i] = inf, pre[i] = i;
                for(int j = 1; j <= n; j++) if(!inc[j] && w[j][i] < w[pre[i]][i]) {
                    pre[i] = j;
                }
            }

            int i;
            for(i = 2; i <= n; i++) if(!inc[i]) {
                int j = i, cnt = 0;
                while(j != 1 && cnt <= n && pre[j] != i) cnt++, j = pre[j];
                if(cnt > n || j == 1) continue;
                break;
            }

            if(i > n) {
                for(int j = 2; j <= n; j++) if(!inc[j]) ans += w[pre[j]][j];
                break;
            }
            memset(vis, 0, sizeof(vis));
            int j = i;
            do{ ans += w[pre[j]][j], j = pre[j], vis[j] = inc[j] = 1; }
            while(j != i);
            inc[i] = 0;

            for(int k = 1; k <= n; k++) if(vis[k]) {
                for(int j = 1; j <= n; j++) if(!vis[j]) {
                    if(w[i][j] > w[k][j]) w[i][j] = w[k][j];
                    if(w[j][k] < inf && w[j][k] - w[pre[k]][k] < w[j][i]) 
                        w[j][i] = w[j][k] - w[pre[k]][k];
                }
            }
        }
        printf("%.2f\n", ans);
    }
}

你可能感兴趣的:(总结)