POJ1679

Problem: The Unique MST
Description: 问最小生成树是否唯一。如果唯一求出最小生成树的值。
Solution: Kruskal或者Prim. 如果用Kruskal算法的话,我们在并查集枚举边枚举到当前边的时候我们向后比较是否存在同当前边距离相同同时父节点也相同的边,如果有,那么最小生成树连边的话就有两种选择,这个时候就不是唯一的了;如果用Prim算法,那么我们就求次小生成树。看次小生成树和最小生成树是否相同。如果相同就不是唯一的了。
Code(C++):

kruskal:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

const int M=105;
const int E=M*(M-1)/2;

typedef struct tagEdge{
    int from,to;
    int value;
}Edge;

Edge edges[E];

int n,m;

int p[M];

int cmp(const void *a,const void *b)
{
    Edge *A=(Edge *)a;
    Edge *B=(Edge *)b;
    return A->value-B->value;
}

int find(int x)
{
    return x==p[x]? x:p[x]=find(p[x]);
}

int kruskal()
{
    bool flag=true;
    int sum=0;

    for(int i=0;i<m;i++){
        int px=find(edges[i].from);
        int py=find(edges[i].to);
        if(px==py)
            continue;
        for(int j=i+1;j<m;j++){
            if(edges[i].value!=edges[j].value)
                break;
            int tmp_px=find(edges[j].from);
            int tmp_py=find(edges[j].to);
            if((tmp_px==px&&tmp_py==py)||(tmp_px==py&&tmp_py==px)){
                flag=false;
                break;
            }
        }
        if(!flag)
            break;
        p[px]=py;
        sum+=edges[i].value;
    }

    if(!flag)
        return -1;
    return sum;
}

int main()
{
    int N;
    for(scanf("%d",&N);N--;){
        scanf("%d%d",&n,&m);
        for(int i=0;i<m;i++)
            scanf("%d%d%d",&edges[i].from,&edges[i].to,&edges[i].value);
        qsort(edges,m,sizeof(edges[0]),cmp);
        for(int i=0;i<=n;i++)
            p[i]=i;

        int ans=kruskal();
        if(ans==-1)
            puts("Not Unique!");
        else
            printf("%d\n",ans);
    }
    return 0;
}

prim:

#include <stdio.h>
#include <string.h>

#define MAX(a,b) ((a)>(b)? (a):(b))
#define MIN(a,b) ((a)<(b)? (a):(b))

const int M=105;

const int INF=0x3f3f3f3f;

int map[M][M];
int n,m;

int dis[M];
bool used[M];

int dp[M][M];
int pre[M];

int stack[M];

int prim(int src)
{
    int top=0;
    int ans=0;

    for(int i=0;i<M;i++){
        for(int j=0;j<M;j++)
            dp[i][j]=0;
        pre[i]=src;
        used[i]=false;
        dis[i]=map[src][i];
    }
    dis[src]=0;
    used[src]=true;

    for(int i=1;i<n;i++){
        int tmp=INF,k=src;
        for(int j=1;j<=n;j++)
            if(!used[j]&&dis[j]<tmp)
                tmp=dis[j],k=j;

        if(k==src)
            break;
        ans+=tmp;
        used[k]=true;

        for(int j=1;j<top;j++)
            dp[k][stack[j]]=dp[stack[j]][k]=MAX(tmp,dp[pre[k]][stack[j]]);
        stack[top++]=k;

        for(int j=1;j<=n;j++)
            if(!used[j]&&dis[j]>map[k][j])
                pre[j]=k,
                dis[j]=map[k][j];
    }

    return ans;
}

int main()
{
    int N;
    for(scanf("%d",&N);N--;){
        scanf("%d%d",&n,&m);

        for(int i=1;i<n;i++)
            for(int j=i+1;j<=n;j++)
                map[i][j]=map[j][i]=INF;
        for(int i=0;i<m;i++){
            int x,y,c;
            scanf("%d%d%d",&x,&y,&c);
            map[x][y]=map[y][x]=c;
        }

        int ans=prim(1);

        int flag=INF;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                if(i!=j&&i!=pre[j]&&j!=pre[i])
                    flag=MIN(flag,map[i][j]-dp[i][j]);
        if(!flag)
            puts("Not Unique!");
        else
            printf("%d\n",ans);
    }
    return 0;
}

你可能感兴趣的:(算法,poj,kruskal,Prim)