sgu323 Aviamachinations

题目大意:n个城市,m个航空公司,k条航线,接下来的k行,就是每条航线的起点终点,对应航空公司和这条线的权重,现在只保留一个航空公司要求仍够可以使所有城市直接或间接相连,对于不属于这个航空公司的航线需要出钱买,价格就是这条线的权重,输出最小的花费,保留哪家航空公司以及要够买的航线数(q),接下来的q行输出要购买的航线的编号
解题思路:先按每条航线对应的花费做最小生成树,然后枚举航空公司(i->1-M),意思是保留第i家航空公司,然后把本身属于这家航空公司的航线连起来,最后按照最小生成树查哪些点没有连起来,再利用最小生成树中对应的边把这两点连起来,答案要求最小值,更新一下就好了。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#define R 200010
const int inf = 1 << 29;
using namespace std;
int counter;
struct edge{
    int u,v,w,air,flag;
}e[R],tree[R];
struct node{
    int parent;
}a[R],nod[R];
int sell[2500][2500],rel[2500];
bool cmp(edge p,edge q)
{
    return p.w<q.w;
}
bool cmp1(int p,int q)
{
    return p<q;
}
void Initial(int N)
{
    for(int i=1;i<=N;i++){
            a[i].parent=i;
    }
}
void Init(int N)
{
    for(int i=1;i<=N;i++){
        nod[i].parent=i;
    }
}
int Find(int k)
{
    if(a[k].parent!=k){
        a[k].parent=Find(a[k].parent);
    }
    return a[k].parent;
}
int find2(int k)
{
    if(nod[k].parent!=k){
        nod[k].parent=find2(nod[k].parent);
    }
    return nod[k].parent;
}
void krus(int N,int K)
{
    Initial(N);
    for(int i=1;i<=K;i++){
        int l=Find(e[i].u);
        int r=Find(e[i].v);
        if(l!=r){
            tree[counter].u=e[i].u;
            tree[counter].v=e[i].v;
            tree[counter].w=e[i].w;
            tree[counter].air=e[i].air;
            tree[counter].flag=e[i].flag;
            counter++;
            a[r].parent=a[l].parent;
        }
    }
}
void Compute(int M,int N,int K)
{
    int s,shu;
    int ans=inf,buy;
    for(int i=1;i<=M;i++){
        s=1;
        int tmp=0;
        Init(N);
        for(int j=1;j<=K;j++){
            if(e[j].air==i){
                int l=find2(e[j].u);
                int r=find2(e[j].v);
                if(l!=r){
                    nod[r].parent=nod[l].parent;
                }
            }
        }
        for(int k=1;k<counter;k++){

            int u=tree[k].u,v=tree[k].v;
            int l=find2(u);
            int r=find2(v);
            if(l!=r){
            sell[i][s]=tree[k].flag;
            s++;
            tmp+=tree[k].w;
            nod[r].parent=nod[l].parent;
            }
        }
        if(ans>tmp){
            ans=tmp;
            buy=i;
            shu=s-1;
        }
    }
    for(int i=1;i<=shu;i++){
        rel[i]=sell[buy][i];
    }
    printf("%d %d %d\n",ans,buy,shu);
    sort(rel+1,rel+shu+1,cmp1);
    for(int i=1;i<=shu;i++){
        printf("%d\n",rel[i]);
    }
}
int main()
{
    int N,M,K;
    while(~scanf("%d%d%d",&N,&M,&K)){
        counter=1;
        for(int i=1;i<=K;i++){
            scanf("%d%d%d%d",&e[i].u,&e[i].v,&e[i].air,&e[i].w);
            e[i].flag=i;
        }
        sort(e+1,e+K+1,cmp);
        krus(N,K);
        Compute(M,N,K);
    }
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值