UVa 10807 Prim(最小生成樹+二進制枚舉)

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 Input Sample Output
2
3
1 2 10
2 1 20
1 2 30
3
3
1 2 10
1 2 20
2 3 50
5
8
1 2 10
1 3 10
1 4 10
1 4 20
1 5 20
2 3 20
3 4 20
4 5 30
0
30
No way!
140

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

1 2 10
1 3 10
1 4 10
1 5 20
and let company B keep these ones:
1 4 20
2 3 20
3 4 20
4 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;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章