UVa 10807 Prim(最小生成树+二进制枚举)

来源:互联网 发布:好的幼儿教育软件app 编辑:程序博客网 时间:2024/05/29 17:19

10807 - Prim

Time limit: 3.000 seconds

Problem ?
Prim, Prim.
Time Limit: 3 seconds

Calax Research and Development is a large high tech corporation. They have an antitrust lawsuit on their hands because they are too big. The judge has ordered that the corporation be split into two new companies, A and B.

Calax has a large network of communication lines that connect a number of cities (each city is connected to every other city by a path of communication lines). They now need to split those lines into two sets, A and B. It is important that each of the two sets still connects all of the cities because the two companies will not be allowed to share communication lines. It has also been decided that all redundant lines will be sold off to protect the two new companies from more antitrust lawsuits. And of course, the total cost of this operation needs to be as small as possible.

Input
The input will contain a number of cases. Each case will begin with n - the number of cities (at most 10), followed by m - the number of communication lines (at most 25). The next m lines will contain 3 numbers each - the two cities connected by the line and the cost of keeping the line. Each city will be identified by an integer in the range [1,n]. The cost of a line is at most 1000. The input will be terminated by the case where n is zero.

Output
Output one integer per test case on a line by itself - the minimum total cost of the communication lines in sets A and B. Print "No way!" if there is no solution.

Sample InputSample Output
231 2 102 1 201 2 30331 2 101 2 202 3 50581 2 101 3 101 4 101 4 201 5 202 3 203 4 204 5 300
30No way!140

Comments
In the third test case, one possible solution is to let company A keep these communication lines:

1 2 101 3 101 4 101 5 20
and let company B keep these ones:
1 4 202 3 203 4 204 5 30
for a total cost of 50 + 90 = 140.



题意 : 给你一个有重边的图,生成2个无重边的总权值最小的生成树,输出最小总权值。

思路 : 首先在原图中做一遍Kruskal ,求出最小生成树。再在所求的最小生成树求出必要

边(必要边就是求掉该边,原图的最小生成树的总权值变大)。可知,必要边一定在最后

所选的2个生成树(A和B中。所以枚举必要边分别在A,B中,对每一种情况求A的最小生

成树a和B的最小生成树b ,ans=min(a+b);


#include <iostream>#include <algorithm>#include <cstdio>#include <cstring>using namespace std;const int inf=9999999;const int maxn=35;struct node{    int u,v,val;}a[maxn];int id[maxn],b[maxn],c[maxn],f[maxn],coun,cnt,num,n,m;bool visited[maxn];bool cmp(node p,node q){     return p.val<q.val;}int Find(int x){    if(x!=id[x]) id[x]=Find(id[x]);    return id[x];}void initial(){    cnt=0;    num=0;    memset(visited,0,sizeof(visited));}void input(){    scanf("%d",&m);    for(int i=0;i<m;i++)  scanf("%d %d %d",&a[i].u,&a[i].v,&a[i].val);    sort(a,a+m,cmp);}int kru(int t){    int ret=0;    for(int i=0;i<n+2;i++)  id[i]=i;    for(int i=0;i<m;i++)    {         int p=Find(a[i].u),q=Find(a[i].v);         if(p!=q && !visited[i])         {            if(t==1)  b[cnt++]=i;            if(t==3)  f[coun++]=i;            ret+=a[i].val;            id[p]=q;         }    }    int tp=Find(1);    for(int i=1;i<=n;i++)  if(Find(i)!=tp)  return inf;    return ret;}int deal(int co){    int tp=0,d[maxn];    for(int j=0;j<num;j++)  if(co & (1<<j)) d[tp++]=c[j];    memset(visited,0,sizeof(visited));    for(int i=0;i<tp;i++)  visited[d[i]]=1;    coun=0;    int x1=kru(3);    for(int i=0;i<coun;i++)  visited[f[i]]=1;    for(int i=0;i<tp;i++)  visited[d[i]]=0;    int x2=kru(2);    return x1+x2;}void solve(){    int ret=kru(1);    for(int i=0;i<cnt;i++)    {        memset(visited,0,sizeof(visited));        visited[b[i]]=1;        int tp=kru(2);        if(ret<tp) c[num++]=b[i];    }    int len=1<<num,ans=inf;    for(int i=0;i<len;i++)  ans=min(ans,deal(i));    if(ans>=inf)  printf("No way!\n");    else  printf("%d\n",ans);}int main(){    while(scanf("%d",&n)!=EOF)    {        if(n==0)  break;        initial();        input();        solve();    }    return 0;}


0 0