UVA 10462 Is There A Second Way Left?(Kruskal算法/Prim算法)

来源:互联网 发布:2017淘宝双11技术汇总 编辑:程序博客网 时间:2024/06/08 02:00

【题意】

给一个含有n个点,cnt条边的图(1<= n <= 100,0 <= cnt <= 200),问次小生成树是多少,如果无法生成次小生成树,输出No second way,如果最小生成树也无法生成,输出No way。


【思路】

直接Kruskal或Prim算法求一下最小生成树,然后枚举这棵生成树中的边剔除来生成次小生成树。注意Prim算法,若用链式前向星来建图,由于是双向边,所以数组还得开得更大些。


【代码1】

#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int MAXN=105,INF=0x3f3f3f3f;struct edge{    int from,to,cost;    bool operator<(const edge &another)const    {        return cost<another.cost;    }};int t,n,cnt;int fa[MAXN];edge e[2*MAXN];bool used[2*MAXN];void init(){    for(int i=1;i<=n;i++)        fa[i]=i;}int findfather(int x){    return (x==fa[x]?x:fa[x]=findfather(fa[x]));}int kruskal(int x){    init();    if(x==0){        memset(used,false,sizeof(used));        int tot=0,ans=0;        for(int i=1;i<=cnt;i++){            int p,q;            p=findfather(e[i].from);            q=findfather(e[i].to);            if(p!=q){                fa[q]=p;                used[i]=true;                tot++;                ans+=e[i].cost;                if(tot==n-1)return ans;            }        }        return INF;    }    else{        int tot=0,ans=0;        for(int i=1;i<=cnt;i++){            if(i==x)continue;            int p,q;            p=findfather(e[i].from);            q=findfather(e[i].to);            if(p!=q){                fa[q]=p;                tot++;                ans+=e[i].cost;                if(tot==n-1)return ans;            }        }        return INF;    }}int main(){    scanf("%d",&t);    for(int kase=1;kase<=t;kase++){        scanf("%d %d",&n,&cnt);        for(int i=1;i<=cnt;i++){            int a,b,c;            scanf("%d %d %d",&a,&b,&c);            e[i].from=a;            e[i].to=b;            e[i].cost=c;        }        sort(e+1,e+1+cnt);        if(kruskal(0)==INF&&n>1){            printf("Case #%d : No way\n",kase);            continue;        }        int ans=INF;        for(int i=1;i<=cnt;i++)            if(used[i])ans=min(ans,kruskal(i));        if(ans==INF)            printf("Case #%d : No second way\n",kase);        else            printf("Case #%d : %d\n",kase,ans);    }    return 0;}


【代码2】

#include<cstdio>#include<cstring>#include<algorithm>#include<queue>using namespace std;const int MAXN=105,INF=0x3f3f3f3f;struct edge{    int from,to,cost,next;};int t,n,m,cnt,minpoint,minlen,minnum;int head[MAXN];bool visited[MAXN],used[4*MAXN];edge e[4*MAXN];queue<int> q;void addedge(int from,int to,int cost){    cnt++;    e[cnt].to=to;    e[cnt].cost=cost;    e[cnt].next=head[from];    head[from]=cnt;}void findone(int x){    int y=(x&1?x+1:x-1);    if(!q.empty()){        int u=q.front();q.pop();        for(int i=head[u];i!=0;i=e[i].next){            if(i==x||i==y)continue;            int v=e[i].to;            if(!visited[v]&&minlen>e[i].cost){                minlen=e[i].cost;                minpoint=v;                minnum=i;            }        }        findone(x);        q.push(u);    }}int prim(int x){    memset(visited,false,sizeof(visited));    while(!q.empty())q.pop();    q.push(1);    visited[1]=true;    int ans=0,tot=1;    minlen=INF;    findone(x);    if(x==0){        memset(used,false,sizeof(used));        while(minlen!=INF){            int v=minpoint;            q.push(v);            visited[v]=true;            used[minnum]=true;            if(minnum&1)                used[minnum+1]=true;            else                used[minnum-1]=true;            ans+=minlen;            tot++;            if(tot==n)break;            minlen=INF;            findone(x);            v=minpoint;        }    }    else{        while(minlen!=INF){            int v=minpoint;            q.push(v);            visited[v]=true;            ans+=minlen;            tot++;            if(tot==n)break;            minlen=INF;            findone(x);        }    }    if(tot!=n)ans=INF;    return ans;}int main(){    scanf("%d",&t);    for(int kase=1;kase<=t;kase++){        scanf("%d %d",&n,&m);        memset(head,0,sizeof(head));        cnt=0;        for(int i=1;i<=m;i++){            int a,b,c;            scanf("%d %d %d",&a,&b,&c);            addedge(a,b,c);            addedge(b,a,c);        }        if(prim(0)==INF){            printf("Case #%d : No way\n",kase);            continue;        }        int ans=INF;        for(int i=1;i<=cnt-1;i+=2)            if(used[i])ans=min(ans,prim(i));        if(ans==INF)            printf("Case #%d : No second way\n",kase);        else            printf("Case #%d : %d\n",kase,ans);    }    return 0;}


原创粉丝点击