次小生成树

次小生成树:通过交换一条最小生成树上的边

求解次小生成树可通过Kruskal算法和prime算法延伸得到:

1、Kruskal 算法求得的过程就是多次求最小生成树。我们第一次求最小生成树的时候把边的序号都记下来,然后以后多次求最小生成树的时候,每次都不用第一次求得的最小生成树的边。比如说,第一次求最小生成树用到了边1 6 7,则我们再次求3次最小生成树,第一次不用边1,第二次不用边6,第三次不用边7,若中间有哪一次和第一次的和相等,则说明不唯一,否则,唯一。(ps:自己还没有用Kruskal算法写过,下次有机会补上)

2、用prime算法求最小生成树的过程是先求一遍最小生成树,在求得过程中我们设置一个pre数组,表示的是某个点的前驱,比如说刚开始选到点1,然后选到的第一条边是从1到3的,则pre[3] = 1,并且在求最小生成树的过程中把选到的边记录下来。我们再设置另一个数组maxedge,表示在构造好的树中,如果x和y之间有一条边,且该边没有在最小生成树中,则maxedge[x][y]表示加上这条边后,所能去掉的最大的边。比如说,我们求出一颗最小生成树后,此时x和y有一条边,且这条边没有被用到,此时maxedge[x][y]表示生成树中从x到y的路径中最大的一条边,也就是说连接x和y的路径中能够去掉的最大的边,也就是说求出最小生成树后,再遍历图中所有没有用到的边求次小生成树即可。如果某个值 和最小生成树的值相同,则最小生成树不唯一,否则最小生成树唯一。

View Code
const int MAXN = 110;
const int INF = 0x3f3f3f3f;
int N, M;
int g[MAXN][MAXN], dist[MAXN];
bool vis[MAXN], use[MAXN][MAXN];
int ans, pre[MAXN], maxedge[MAXN][MAXN];

void prime(int n) {
    for(int i = 1; i <= n; i++)
        dist[i] = INF;
    dist[1] = 0;
    for(int i = 1; i <= n; i++)
        pre[i] = i;

    for(int i = 1; i <= n; i++) {
        int min_dis = INF;
        int idx;
        for(int j = 1; j <= n; j++) {
            if(!vis[j] && min_dis > dist[j]) {
                min_dis = dist[j];
                idx = j;
            }
        }
        for(int j = 1; j <= n; j++) if(vis[j]) {
            maxedge[idx][j] = maxedge[j][idx] = max(maxedge[j][pre[idx]], dist[idx]);
        }
        vis[idx] = 1;
        use[idx][pre[idx]] = use[pre[idx]][idx] = 1;
        ans += min_dis;
        for(int j = 1; j <= n; j++) {
            if(!vis[j] && dist[j] > g[idx][j]) {
                dist[j] = g[idx][j];
                pre[j] = idx;
            }
        }
    }
}

int smst(int n) {

    int Min = INF;
    for(int i = 1; i <= n; i++) {
        for(int j = i+1; j <= n; j++) {
            if(g[i][j] != INF && !use[i][j]) {
                int res = ans + g[i][j] - maxedge[i][j];
                Min = min(Min, res);
            }
        }
    }
    if(Min == ans) return 0;
    return 1;
}

void init() {
    ans = 0;
    memset(use, false, sizeof(use));
    memset(vis, false, sizeof(vis));
    memset(maxedge, 0, sizeof(maxedge));
    for(int i = 0; i < MAXN; i++) {
        for(int j = 0; j < MAXN; j++) {
            g[i][j] = INF;
        }
    }
}

以下几题是较为基础的题,套下模板即可,不过读题很重要(第二题一开始都没看出来是次小生成树问题)

1、poj1679The Unique MST(此题较为经典)

View Code
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
using namespace std;

const int MAXN = 110;
const int INF = 0x3f3f3f3f;
int N, M;
int g[MAXN][MAXN], dist[MAXN];
bool vis[MAXN], use[MAXN][MAXN];
int ans, pre[MAXN], maxedge[MAXN][MAXN];

void prime(int n) {
    for(int i = 1; i <= n; i++)
        dist[i] = INF;
    dist[1] = 0;
    for(int i = 1; i <= n; i++)
        pre[i] = i;

    for(int i = 1; i <= n; i++) {
        int min_dis = INF;
        int idx;
        for(int j = 1; j <= n; j++) {
            if(!vis[j] && min_dis > dist[j]) {
                min_dis = dist[j];
                idx = j;
            }
        }
        for(int j = 1; j <= n; j++) if(vis[j]) {
            maxedge[idx][j] = maxedge[j][idx] = max(maxedge[j][pre[idx]], dist[idx]);
        }
        vis[idx] = 1;
        use[idx][pre[idx]] = use[pre[idx]][idx] = 1;
        ans += min_dis;
        for(int j = 1; j <= n; j++) {
            if(!vis[j] && dist[j] > g[idx][j]) {
                dist[j] = g[idx][j];
                pre[j] = idx;
            }
        }
    }
}

int smst(int n) {

    int Min = INF;
    for(int i = 1; i <= n; i++) {
        for(int j = i+1; j <= n; j++) {
            if(g[i][j] != INF && !use[i][j]) {
                int res = ans + g[i][j] - maxedge[i][j];
                Min = min(Min, res);
            }
        }
    }
    if(Min == ans) return 0;
    return 1;
}

void init() {
    ans = 0;
    memset(use, false, sizeof(use));
    memset(vis, false, sizeof(vis));
    memset(maxedge, 0, sizeof(maxedge));
    for(int i = 0; i < MAXN; i++) {
        for(int j = 0; j < MAXN; j++) {
            g[i][j] = INF;
        }
    }
}

int main()
{
    int T;
    scanf("%d", &T);
    while(T--) {
        init();
        scanf("%d%d", &N, &M);
        for(int i = 1; i <= M; i++) {
            int u, v, c;
            scanf("%d%d%d", &u, &v, &c);
            if(g[u][v] > c)
                g[u][v]= g[v][u] = c;
        }
        prime(N);
        if(smst(N)) {
            printf("%d\n", ans);
        }
        else
            puts("Not Unique!");
    }
    return 0;
}

 2、hdu4081Qin Shi Huang's National Road System

View Code
#include <iostream>
#include <cmath>
#include <cstring>
#include <string>
#include <cstdio>
#define MAXN 1010
using namespace std;
const double INF = 999999999;
int pre[MAXN];
double dist[MAXN], g[MAXN][MAXN], maxedge[MAXN][MAXN];
bool vis[MAXN], use[MAXN][MAXN];
double  ans;

struct Point {
    double x, y;
    int c;
}node[MAXN];

double get_len(const Point &a, const Point &b) {
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}

void init() {
    ans = 0;
    memset(vis, false, sizeof(vis));
    memset(use, false, sizeof(use));
    memset(maxedge, 0, sizeof(maxedge));
    for(int i = 0; i < MAXN; i++) {
        for(int j = 0; j < MAXN; j++) {
            g[i][j] = INF;
        }
    }
}

void prime(int n) {

    for(int i = 1; i <= n; i++)
        dist[i] = INF;
    dist[1] = 0;
    for(int i = 1; i <= n; i++)
        pre[i] = i;

    for(int i = 1; i <= n; i++) {
       double min_dis = INF;
        int idx;
        for(int j = 1; j <= n; j++) {
            if(!vis[j] && min_dis > dist[j]) {
                min_dis = dist[j];
                idx = j;
            }
        }
        for(int j = 1; j <= n; j++) if(vis[j]) {
            maxedge[idx][j] = maxedge[j][idx] = max(maxedge[j][pre[idx]], dist[idx]);
        }
        vis[idx]= 1;
        use[idx][pre[idx]] = use[pre[idx]][idx] =1;
        ans += min_dis;
        for(int j = 1; j <= n; j++) {
            if(!vis[j] && dist[j] > g[idx][j]) {
                dist[j] = g[idx][j];
                pre[j] = idx;
            }
        }
    }

}

double cal(int n) {
    double ratio = 0;
    int A;
    double B;

    for(int i = 1; i <= n; i++) {
        for(int j = 1; j <= n; j++) if(i != j){
            A = node[i].c + node[j].c;
            if(use[i][j]) {
                B = ans - g[i][j];
            }
            else {
                if(g[i][j] != INF) {
                    B = ans - maxedge[i][j];
                }
            }
            ratio = max(ratio,1.0*A/B);
        }
    }
    return ratio;
}

int main()
{
    int T, n;
    scanf("%d", &T);
    while(T--) {
        init();
        scanf("%d", &n);
        for(int i = 1; i <= n; i++) {
            scanf("%lf %lf%d", &node[i].x, &node[i].y, &node[i].c);
        }

        for(int i = 1; i <= n; i++) {
            for(int j = 1; j <= n; j++) {
                g[i][j] = get_len(node[i], node[j]);
            }
        }
        prime(n);
        printf("%.2lf\n", cal(n));
    }
    return 0;
}

 

 

 

posted on 2013-02-05 16:31  Lavare  阅读(184)  评论(0)    收藏  举报

导航