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

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

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

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

 

posted @ 2019-07-13 14:48  alusang  阅读(271)  评论(0编辑  收藏  举报