次小生成树

和最小生成树一块整理了吧,就简单的几个模板题。
上一篇文末已推荐两个次小生成树链接,此处不再引用。


UVa 10600(由于UVa访问较慢,这里给出Vjudge的链接)

In order to prepare the \The First National ACM School Contest” (in 20??) the major of the city
decided to provide all the schools with a reliable source of power. (The major is really afraid of
blackoutsJ). So, in order to do that, power station \Future” and one school (doesn’t matter which one)
must be connected; in addition, some schools must be connected as well.
You may assume that a school has a reliable source of power if it’s connected directly to \Future”,
or to any other school that has a reliable source of power. You are given the cost of connection between
some schools. The major has decided to pick out two the cheapest connection plans { the cost of the
connection is equal to the sum of the connections between the schools. Your task is to help the major - find the cost of the two cheapest connection plans.
Input
The Input starts with the number of test cases, T
(1<T<15) on a line. ThenT
test cases follow. The rst line of every test case contains two numbers, which are separated by a space,N (3<N<100)
the number of schools in the city, and M
the number of possible connections among them. Next M
lines contain three numbers Ai , Bi , Ci , where Ci
is the cost of the connection (1<Ci<300) between
schools Ai and Bi . The schools are numbered with integers in the range 1 toN.
Output
For every test case print only one line of output. This line should contain two numbers separated by a
single space { the cost of two the cheapest connection plans. Let
S1 be the cheapest cost and S2 thenext cheapest cost. It’s important, that S1=S2 if and only if there are two cheapest plans, otherwise S1<S2 . You can assume that it is always possible to nd the costs S1 and S2 .
SampleInput
2
5 8
1 3 75
3 4 51
2 4 19
3 2 95
2 5 42
5 4 31
1 2 9
3 5 66
9 14
1 2 4
1 8 8
2 8 11
3 2 8
8 9 7
8 7 1
7 9 6
9 3 2
3 4 7
3 6 4
7 6 2
4 6 14
4 5 9
5 6 10
SampleOutput
110 121
37 37

/*
 *UVa 10600
 *Time 0
 *
*/
#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;
const int MAXN = 102;
const int MAXE = 10002;
const int INF = 1<<30;
struct Side{//边集
    int from, to, wei;
    bool vis;
    bool operator < (const struct Side s)const {
        return wei < s.wei;
    }
}side[MAXE];

struct Edge{//邻接表
    int to, next, wei;
}edge[MAXE];

int sideNum, edgeNum;//边的数目、邻接表的长度
int head[MAXN], Map[MAXN][MAXN];//邻接表表头、Map记录Pi-Pj的最长边

void addSide(int u, int v, int w);//添加边集
void addEdge(int u, int v, int w);//邻接表中添边
void slove(int n, int m);
int kruskal(int n, int m);
bool Union(const struct Side &s, int *root);
int Find(int p, int *root);
void BFS(int s, int n);//广搜得到生成树中Pi-Pj的最长边

int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(0);
    int t, n, m;
    int u, v, w;
    cin>>t;
    while(t--) {
        cin>>n>>m;
        sideNum = edgeNum = 0;
        for(int i = 0; i < m; ++i) {
            cin>>u>>v>>w;
            addSide(u, v, w);
        }
        slove(n, m);
    }
    return 0;
}
void addSide(int u, int v, int w)
{
    side[sideNum].vis = false;
    side[sideNum].from = u;
    side[sideNum].to = v;
    side[sideNum].wei = w;
    sideNum++;
}
void addEdge(int u, int v, int w)
{
    edge[edgeNum].to = v;
    edge[edgeNum].wei = w;
    edge[edgeNum].next = head[u];
    head[u] = edgeNum++;
}
void slove(int n, int m)
{
    int Min = kruskal(n, m);//求最小生成树
    for(int i = 0; i <= n; ++i) head[i] = -1;
    for(int i = 0; i <= n; ++i)
        for(int j = 0; j <= n; ++j)
            Map[i][j] = 0;
    for(int i = 0; i < sideNum; ++i) {//将生成树的边加入到邻接表
        if(side[i].vis) {
            addEdge(side[i].from, side[i].to, side[i].wei);
            addEdge(side[i].to, side[i].from, side[i].wei);
        }
    }
    for(int i = 1; i <= n; ++i)//得到生成树中的最长边
        BFS(i, n);
    int secMin = INF;
    for(int i = 0; i < sideNum; ++i) {
        if(!side[i].vis) {//枚举不属于生成树的边
            int u = side[i].from;
            int v = side[i].to;
            if(secMin > Min + side[i].wei - Map[u][v])//更新次小值
                secMin = Min + side[i].wei - Map[u][v];
        }
    }
    cout<<Min<<" "<<secMin<<endl;
}
int kruskal(int n, int m)
{
    int Min = 0, node = n - 1;
    int root[MAXN];
    for(int i = 0; i <= n; ++i) root[i] = i;
    sort(side, side + sideNum);
    for(int i = 0; node && i < sideNum; ++i) {
        if(Union(side[i], root)) {
            node--;
            Min += side[i].wei;
            side[i].vis = true;
        }
    }
    return Min;
}
bool Union(const struct Side &s, int *root)
{
    int p = Find(s.from, root);
    int q = Find(s.to, root);
    if(p != q) {
        root[p] = q;
        return true;
    }
    return false;
}
int Find(int p, int *root)
{
    while(p != root[p]) {
        root[p] = root[root[p]];
        p = root[p];
    }
    return p;
}
void BFS(int s, int n)
{
    bool vis[MAXN];
    queue<int> q;
    for(int i = 0; i <= n; ++i) vis[i] = false;
    vis[s] = true, q.push(s);
    while(!q.empty()) {
        int u = q.front();
        q.pop();
        for(int i = head[u]; i != -1; i = edge[i].next) {
            int v = edge[i].to;
            if(!vis[v]) {
                vis[v] = true, q.push(v);
                Map[s][v] = Map[s][u] > edge[i].wei?Map[s][u]: edge[i].wei;//s-v的最长边
            }
        }
    }
}

UVa 10462

Nasa, being the most talented programmer of his time, can’t think things to be so simple. Recently all
his neighbors have decided to connect themselves over a network (actually all of them want to share
a broadband internet connection :-)). But he wants to minimize the total cost of cable required as he
is a bit fastidious about the expenditure of the project. For some unknown reasons, he also wants a
second way left. I mean, he wants to know the second best cost (if there is any which may be same as
the best cost) for the project. I am sure, he is capable of solving the problem. But he is very busy with
his private affairs(?) and he will remain so. So, it is your turn to prove yourself a good programmer.
Take the challenge (if you are brave enough)…
Input
Input starts with an integer t1000 which denotes the number of test cases to handle. Then follows
t datasets where every dataset starts with a pair of integers v
(1v100) and e (0e200) . v
denotes the number of neighbors and e denotes the number of allowed direct connections among them.
The following e lines contain the description of the allowed direct connections where each line is of the
form ‘start end cost’, where start and end are the two ends of the connection and cost is the cost for
the connection. All connections are bi-directional and there may be multiple connections between two
ends.
Output
There may be three cases in the output
1. No way to complete the task,
2. There is only one way to complete the task,
3. There are more than one way.
Output ‘No way’ for the first case, ‘No second way’ for the second case and an integer c for the
third case where c is the second best cost. Output for a case should start in a new line.
Sample Input
4
5 4
1 2 5
3 2 5
4 2 5
5 4 5
5 3
1 2 5
3 2 5
5 4 5
5 5
1 2 5
3 2 5
4 2 5
5 4 5
4 5 6
1 0
Sample Output
Case #1 : No second way
Case #2 : No way
Case #3 : 21
Case #4 : No second way

/*
 *UVa 10462
 *Time 20
 *数据结构算法与上一题相同
 *此处需要额外考虑不连通的情况,以及只有一棵树的情况。
*/
#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;
const int MAXN = 102;
const int MAXE = 204;
const int INF = 1<<30;
struct Side{
    int from, to, wei;
    bool inTree;
    bool operator <(const struct Side &s) const{
        return wei < s.wei;
    }
}side[MAXE];
struct Edge{
    int to, wei, next;
}edge[MAXE];
int root[MAXN], head[MAXN], Map[MAXN][MAXN];
int sideNum, edgeNum;
void addSide(int u, int v, int wei);
void addEdge(int u, int v, int wei);
void slove(int n, int m);
int kruskal(int n, int m, int &node);
bool Unioned(struct Side &s);
int Find(int p);
void BFS(int s, int n);
int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(0);
    int t, n, m;
    int u, v, w;
    cin>>t;
    for(int C = 1; C <= t; ++C) {
        cin>>n>>m;
        sideNum = edgeNum = 0;
        for(int i = 0; i < m; ++i) {
            cin>>u>>v>>w;
            addSide(u, v, w);
        }
        cout<<"Case #"<<C<<" : ";
        slove(n, m);
    }
    return 0;
}
void addSide(int u, int v, int wei)
{
    side[sideNum].from = u;
    side[sideNum].to = v;
    side[sideNum].wei = wei;
    side[sideNum].inTree = false;
    sideNum++;
}
void addEdge(int u, int v, int wei)
{
    edge[edgeNum].to = v;
    edge[edgeNum].wei = wei;
    edge[edgeNum].next = head[u];
    head[u] = edgeNum++;
}
void slove(int n, int m)
{
    int node = n - 1;
    for(int i = 0; i <= n; ++i) root[i] = i, head[i] = -1;
    for(int i = 0; i <= n; ++i)
        for(int j = 0; j <= n; ++j)
            Map[i][j] = 0;

    int Min = kruskal(n, m, node), secMin = INF;

    for(int i = 0; i < m; ++i) {
        if(side[i].inTree) {
            addEdge(side[i].from, side[i].to, side[i].wei);
            addEdge(side[i].to, side[i].from, side[i].wei);
        }
    }

    for(int i = 1; i <= n; ++i)
        BFS(i, n);
    if(node != 0 && n > 1) {//不连通
        cout<<"No way"<<endl;
        return ;
    }
    if(edgeNum / 2 == m) {//只用一棵树
        cout<<"No second way"<<endl;
        return ;
    }
    for(int i = 0; i < m; ++i) {
        if(!side[i].inTree) {
            int u = side[i].from, v = side[i].to;
            int dist = Min + side[i].wei - Map[u][v];
            secMin = secMin < dist? secMin: dist;
        }
    }
    cout<<secMin<<endl;
}
int kruskal(int n, int m, int &node)
{
    int sum = 0;
    sort(side, side + m);
    for(int i = 0; node && i < m; ++i) {
        if(Unioned(side[i])) {
            node--;
            sum += side[i].wei;
            side[i].inTree = true;
        }
    }
    return sum;
}
bool Unioned(struct Side &s)
{
    int p = Find(s.from), q = Find(s.to);
    if(p != q) {
        root[p] = q;
        return true;
    }
    return false;
}
int Find(int p)
{
    while(p != root[p]) {
        root[p] = root[root[p]];
        p = root[p];
    }
    return p;
}
void BFS(int s, int n)
{
    bool vis[MAXN];
    queue<int> Q;
    for(int i = 0; i <= n; ++i) vis[i] = false;
    Q.push(s), vis[s] = true;
    while(!Q.empty()) {
        int u = Q.front();
        Q.pop();
        for(int i = head[u]; i != -1; i = edge[i].next) {
            int v = edge[i].to;
            if(!vis[v]) {
                Map[s][v] = Map[s][u] > edge[i].wei? Map[s][u]: edge[i].wei;
                Q.push(v), vis[v] = true;
            }
        }
    }
}

最后再推荐一个生成树的题目集,听过kuangbin很厉害哟(是真的厉害)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值