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;
}
时间: 2024-11-06 09:32:24

UVa 10807 Prim(最小生成树+枚举)的相关文章

HDU4081 Qin Shi Huang&#39;s National Road System【prim最小生成树+枚举】

先求出最小生成树,然后枚举树上的边,对于每条边"分别"找出这条割边形成的两个块中点权最大的两个 1.由于结果是A/B,A的变化会引起B的变化,两个制约,无法直接贪心出最大的A/B,故要通过枚举 2.不管magic road要加在哪里,加的边是否是最小生成树上的边,都会产生环,我们都要选择一条边删掉 注意删掉的边必须是树的环上的边,为了使结果最大,即找出最大的边 3.可以枚举两点,找出边,也可以枚举边,找出点,我是用后者,感觉比较容易写也好理解 #include <cstdio&g

UVa 725 Division --- 简单枚举

题目链接: https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=666 /* UVa 725 Division --- 简单枚举 */ #include <cstdio> #include <cstring> bool used[10]; /* 判断传进来的两个数是否满足条件 */ bool judge(int a, i

UVa 11354 Bond 最小生成树+LCA倍增

题目来源:UVa 11354 Bond 题意:n个点m条边的图 q次询问 找到一条从s到t的一条边 使所有边的最大危险系数最小 思路:使最大的危险系数尽量小 答案是最小生成树上的边 然后用LCA倍增法记录s和t到他们最近公共祖先的最大值 #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn = 50010; const int INF =

uva 11354 bond 最小生成树

n个城市通过m条无向边连接,回答q个询问,每个询问形式为s,t,要找到一条s到t的路使得这条路上的最大危险系数最小. 还是最小瓶颈路,可是要快速回答每次询问,先求出最小生成树,转化为有根树,即找到s到t的路径上的最大边,在这一过程中倍增查找. 预处理的复杂度为nlogn,每次查询为logn. #include <cstdio> #include <cstring> #include <vector> #include <algorithm> using na

Ural 1982 Electrification Plan (prim最小生成树)

很明显的最小生成树模板题 多点生成 [cpp] view plaincopy #include<bits/stdc++.h> using namespace std; int n,k,a; int dist[120],m[120][120]; bool p[120]; void prim() { for(int i=1;i<=n;i++) { if(!p[i]) { int Min=100020; for(int j=1;j<=n;j++) { if(p[j]&&m

Prim 最小生成树算法

Prim 算法是一种解决最小生成树问题(Minimum Spanning Tree)的算法.和 Kruskal 算法类似,Prim 算法的设计也是基于贪心算法(Greedy algorithm). Prim 算法的思想很简单,一棵生成树必须连接所有的顶点,而要保持最小权重则每次选择邻接的边时要选择较小权重的边.Prim 算法看起来非常类似于单源最短路径 Dijkstra 算法,从源点出发,寻找当前的最短路径,每次比较当前可达邻接顶点中最小的一个边加入到生成树中. 例如,下面这张连通的无向图 G,

poj 2485(prim最小生成树)

Highways Description The island nation of Flatopia is perfectly flat. Unfortunately, Flatopia has no public highways. So the traffic is difficult in Flatopia. The Flatopian government is aware of this problem. They're planning to build some highways

uva Fire Station(FLODY+枚举)(挺不错的简单题)

消防站 题目链接:Click Here~ 题意分析: 就是给你f个消防站,n个路口.要你求出在已有消防站的基础上在n个路口的哪个路口上在建立一个消防站,使得n个路口的到离自己最近的消防站最近的距离中最大的一个值最小.即:求n个最近路口中最大的一个,使其改最大值最小.详细的要求自己看题目吧~ 算法分析: 因为,是n个路口到每个消防站的距离.所以,我们可以想到先用一次Flody算法.把每两点的最近距离给算出来.之后在枚举N个路口,进行判断比较得出答案. #include <iostream> #i

POJ 1258 Agri-Net (prim最小生成树)

最小生成树模板题 #include<bits/stdc++.h> using namespace std; int n,a; int dist[120],m[120][120]; void prim() {     bool p[1020];     for(int i=2;i<=n;i++)     {         p[i]=false;         dist[i]=m[1][i];     }     dist[1]=0,p[1]=true;     for(int i=1;