PAT-Battle Over Cities - Hard Version (35 分)-最小生成树

博客围绕一个问题展开,即假设城市被占领后,求使剩余城市联通的最小花费里花费最多的被占领城市。解题思路是利用最小生成树,依次去掉某个城市的相接路径,将剩余路加入最小生成树求最大值,若去掉城市使连通块增多则花费算无限大。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这个题的题意是假设某个城市被占领后,要使剩下的城市保持联通可能会花钱修路,求最小花费里花费最多的那个被占领的城市。

这个题凭感觉就是最小生成树,最小生成树满足权值最小(最小花费),所以依次去掉某个城市的所有与其相接的路径,把剩下的路加入最小生成树,求最大值即可。

有一个地方写的时候没注意到,就是去掉某个城市后可能导致连通块的数量的增多,这种情况下算这个城市的花费无限大就可以了(自己真菜QAQ)。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
#include <vector>
#include <cmath>

using namespace std;

const int INF = 0x3f3f3f3f;
int n,m,max1;
int f[505];
vector<int> ans;

struct P{
    int u,v,c,s;
    bool operator<(const P &a)const{
        if(s != a.s) return s > a.s;//优先选择还能用的路,这种路径不增加花费
        else return c<a.c;//其实是处理需要修理的路径,先修花费少的
    }
}p[250005];

int Find(int x){
    if(x==f[x]) return x;
    else return f[x]=Find(f[x]);
}

int main(){
    scanf("%d%d",&n,&m);
    max1=0;
    for(int i=1;i<=m;i++)
        scanf("%d%d%d%d",&p[i].u,&p[i].v,&p[i].c,&p[i].s);
    sort(p+1,p+1+m);
    for(int i=1;i<=n;i++){
        int num=0,cnt=0;
        for(int i=1;i<=n;i++) f[i]=i;
        for(int j=1;j<=m;j++){
            if(num==n-2) break;
            int u=p[j].u;
            int v=p[j].v;
            if(u==i || v==i) continue ;//去掉某个城市
            u=Find(u);
            v=Find(v);
            if(u!=v){
                f[u]=v;
                num++;
                if(p[j].s==0) cnt+=p[j].c;
            }
        }
        if(num!=n-2){//先判断删除某个城市后是否连通
            if(max1!=INF){
                max1=INF;
                ans.clear();
            }
            ans.push_back(i);
        }else{
            if(cnt>max1){
                max1=cnt;
                ans.clear();
                ans.push_back(i);
            }else if(cnt==max1 && max1!=0)
                ans.push_back(i);
        }
    }
    if(ans.size()==0) printf("0\n");
    else{
        sort(ans.begin(),ans.end());
        printf("%d",ans[0]);
        for(int i=1;i<ans.size();i++)
            printf(" %d",ans[i]);
    }
    return 0;
}
View Code

 

转载于:https://www.cnblogs.com/JustDoA/p/11180592.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值