The Unique MST

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

题解:次小生成树

C++版本一

Prim算法

/*
*@Author:   STZG
*@Language: C++
*/
//#include 
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
//#define DEBUG
#define RI register int
#define endl "\n"
using namespace std;
typedef long long ll;
//typedef __int128 lll;
const int N=100+10;
const int M=100000+10;
const int MOD=1e9+7;
const double PI = acos(-1.0);
const double EXP = 1E-8;
const int INF = 0x3f3f3f3f;
int t,n,m,k,p,l,r,u,v;
int ans,cnt,flag,temp,sum;
int mapp[N][N];
bool vis[N],connect[N][N];
int dis[N],maxd[N][N],per[N];
void Init()
{
    memset(mapp,INF,sizeof(mapp));
    memset(connect,false,sizeof(connect));
}
int prim()
{
    memset(maxd,0,sizeof(maxd));
    memset(vis,false,sizeof(vis));
    for(int i = 1;i <= n;i ++)
    {
        dis[i] = mapp[1][i];per[i] = 1;//首先父亲节点都是根节点
    }
    vis[1] = 1;
    dis[1] = 0;
    int res = 0;
    for(int i = 1;i < n;i ++){
        int index = -1,temp  = INF;
        for(int j = 1;j <= n;j ++){
            if(!vis[j] && dis[j] < temp){
                index = j;temp = dis[j];
            }
        }
        if(index == -1) return res;
        vis[index] = 1;
        connect[index][per[index]] = false;connect[per[index]][index] = false;//这条边已经在最小生成树中,后面我们就不能添加这条边了
        res += temp;
        maxd[per[index]][index]=maxd[index][per[index]]=temp;//更新点之间的最大值
        for(int j=1;j<=n;j++){
            if(j != index && vis[j]){//只是更新我们已经遍历过来的节点
            maxd[index][j]=maxd[j][index]=max(maxd[j][per[index]],dis[index]);
            }
                if(!vis[j] && mapp[index][j] < dis[j]){
                dis[j] = mapp[index][j];
                per[j] = index;
            }
        }
    }
    return res;
}
int main()
{
#ifdef DEBUG
	freopen("input.in", "r", stdin);
	//freopen("output.out", "w", stdout);
#endif
    //ios::sync_with_stdio(false);
    //cin.tie(0);
    //cout.tie(0);
    //scanf("%d",&t);
    //while(t--){
    int T;
    scanf("%d\n",&T);
    while(T--){
        scanf("%d%d",&n,&m);
        Init();
        int u,v,w;
        for(int i = 0;i < m;i ++){
            scanf("%d%d%d",&u,&v,&w);
            mapp[u][v] = w;mapp[v][u]  = w;
            connect[u][v] = true;connect[v][u] = true;
        }
        int ans = prim();
        bool over = false;
        //如果有某条边没有被最小生成树使用,并且i~j的最大值大于图中得到最大值,那么就表示次小生成树存在
        //相反就不会存在
        for(int i = 1;!over && i <= n;i ++)
        for(int j = 1;j <= n;j ++){
            if(connect[i][j] == false || mapp[i][j] == INF)
                continue;
            if(mapp[i][j] == maxd[i][j])//当边长度相同是就是表示最小生成树相同
            {
                over = 1;
                break;
            }
        }
        if(over)
            printf("Not Unique!\n");
        else
            printf("%d\n",ans);
    }//如果我们需要求解次小生成树的权值时,我们就要把在最小生成树中没有用过的边,加上然后减去对应环中最大的路径
    //}

#ifdef DEBUG
	printf("Time cost : %lf s\n",(double)clock()/CLOCKS_PER_SEC);
#endif
    //cout << "Hello world!" << endl;
    return 0;
}

C++版本二

#include
#include
#include
#define ll long long
#define pb push_back
#define INF 0x3f3f3f3f
#define FI first
#define SE second
#define MP make_pair
#define PI pair
#define lson l,m,rt<<1,ls,rs
#define rson m+1,r,rt<<1|1,ls,rs
#define test printf("here!!!\n")
using namespace std;
const int mx=100+10;
int n,m;
int dis[mx];
int vis[mx];
int mp[mx][mx];
int sum;
int maxd[mx][mx];
int pre[mx];
int connect[mx][mx];
void prim()
{
    sum=0;
    memset(maxd,0,sizeof(maxd));
    memset(connect,0,sizeof(connect));
    for (int i=1;i<=n;++i)
    {
        dis[i]=mp[1][i];
        pre[i]=1;
        vis[i]=0;
    }
    dis[1]=0;
    vis[1]=1;
    int now=1;
    for (int i=1;idis[j])
            {
                minn=dis[j];
                now=j;
            }
        }
        sum+=dis[now];
        vis[now]=1;
        connect[now][pre[now]]=connect[pre[now]][now]=1;
        for (int j=1;j<=n;++j)
        {
            if (vis[j])
            {
                maxd[j][now]=maxd[now][j]=max(maxd[j][pre[now]],dis[now]);
            }
            else if (dis[j]>mp[now][j])
            {
                dis[j]=mp[now][j];
                pre[j]=now;
            }
        }
    }
}
int sprim()
{
    int ans=INF;
    for (int i=1;i<=n;++i)
    {
        for (int j=i+1;j<=n;++j)
        {
            if (!connect[i][j]&&mp[i][j]!=INF)
            {
                ans=min(ans,sum+mp[i][j]-maxd[i][j]);
            }
        }
    }
    return ans;
}
int main()
{
    int x,y,w,t;
    scanf("%d",&t);
    while (t--)
    {
        memset(mp,INF,sizeof(mp));
        scanf("%d%d",&n,&m);
        for (int i=1;i<=m;++i)
        {
            scanf("%d%d%d",&x,&y,&w);
            mp[x][y]=w;
            mp[y][x]=w;
        }
        prim();
        int res=sprim();
        if (sum==res) printf("Not Unique!\n");
        else printf("%d\n",sum);
    }
}

C++版本三

Kruskal算法

#include
#include
#include
#define ll long long
#define pb push_back
#define INF 0x3f3f3f3f
#define FI first
#define SE second
#define MP make_pair
#define PI pair
#define lson l,m,rt<<1,ls,rs
#define rson m+1,r,rt<<1|1,ls,rs
#define test printf("here!!!\n")
using namespace std;
const int mx=1e4+10;
const int MX=5e3+10;
int n,m;
struct Node
{
    int st;
    int to;
    ll w;
    friend bool operator <(const Node &a,const Node &b)
    {
        return a.w>1]+1;
    for (int i=1;i<=n;++i)
    {
        head[i]=0,dis[i]=0,vis[i]=0,pre[i]=i,sz[i]=1;
    }
    memset(ma,0,sizeof(ma));
    memset(fa,0,sizeof(fa));
    memset(use,0,sizeof(use));
    dis[0]=-1;
}
int unfd(int x)
{
    int r=x;
    while (r!=pre[r]) r=pre[r];
    int t;
    while (x!=pre[x])
    {
        t=pre[x];
        pre[x]=r;
        x=t;
    }
    return r;
}
int unjoin(int x,int y)
{
    int fx=unfd(x),fy=unfd(y);
    if (fx!=fy)
    {
        if (sz[fx]dis[v])
    {
        int loog=lg[dis[u]-dis[v]];
        maxn=max(ma[u][loog],maxn);
        u=fa[u][loog];
    }
    if (u==v) return maxn;
    for (int i=lg[dis[u]];i>=0;--i)
    {
        if (fa[u][i]!=fa[v][i])
        {
            maxn=max(max(ma[u][i],ma[v][i]),maxn);
            u=fa[u][i];
            v=fa[v][i];
        }
    }
    return max(max(ma[u][0],ma[v][0]),maxn);
}
int main()
{
    int t;
    scanf("%d",&t);
    while (t--)
    {
        scanf("%d%d",&n,&m);
        int x,y;
        ll z;
        init();
        for (int i=1;i<=m;++i)
        {
            scanf("%d%d%lld",&vec[i].st,&vec[i].to,&vec[i].w);
        }
        sort(vec+1,vec+m+1);
        kruskal();
        dfs(1,0);
        ll ans=0x3f3f3f3f3f3f3f3f;
        for (int i=1;i<=m;++i)
        {
            if (!use[i])
            {
                ans=min(ans,sum-LCA(vec[i].st,vec[i].to)+vec[i].w);
            }
        }
        if (ans==sum) printf("Not Unique!\n");
        else printf("%lld\n",sum);
    }
}

C++版本四

#include 
#include 
#include 
#include 
#include 
#define INF 0x3f3f3f3f
 
using namespace std;
int n,m;
struct data
{
    int u,v,w;
    bool vis;
} p[20010];
vectorG[110];
int per[110],maxd[110][110];
bool cmp(data a,data b)
{
    return a.w < b.w;
}
int Union_Find(int x)
{
    return x == per[x] ? x: per[x] = Union_Find(per[x]);
}
void kruskal()
{
    sort(p,p+m,cmp);
    for(int i=0; i<=n; i++)//初始化
    {
        G[i].clear();
        G[i].push_back(i);
        per[i]=i;
    }
    int sum=0,k=0;//sum是最小生成树的值
    for(int i=0; isum)
        printf("%d\n",sum);
    else
        printf("Not Unique!\n");
}
int main()
{
    int T;
    scanf("%d\n",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);
        for(int i=0; i

 

你可能感兴趣的:(#,C++,C++,次小生成树,Prim,Kruskal)