洛谷P2323 [HNOI2006] 公路修建問題

一位XXS發表於2024-10-08

Problem

給出n個點、m條邊的無向連通圖,每條邊具有2個邊權,一高一低,我們需要選擇若干條邊,使得圖連通的情況下選擇至少k條較高邊權,輸出選擇的邊中,邊權最大值的最小值,輸出答案的一半(保證偶數)

Slove

假設每條邊只具有1條邊權,答案顯而易見,跑一遍最小生成樹即可,因為最小生成樹就是最小瓶頸樹
但是如果存在較高邊權且需要選至少k個,該怎麼辦呢?
注意到,Kruskal演算法的本質就是貪心,每次選擇最小的邊,如果二點未連通,則用並查集合並,否則跳過,直到選擇n-1條邊
所以此時我們可以將所有邊權都遍歷一遍,當選擇較高邊權時k-1,如果k=還需要選擇的邊時,跳過所有較低邊權......嗎?
不難發現,此時最小生成樹=最小瓶頸樹不再適用,但我們可以按照這種貪心思路,優先選擇k條較高邊權,然後再根據需要選擇剩下的邊權(也包括較高邊權,因為有時某一條邊的較低邊權可能比另一條邊的較高邊權還要高!)。因為k條高階邊始終是要選擇的,且高於低階邊權。
時間複雜度就是Kruskal的時間複雜度,為\(O(nlogn)\)

Code

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<string>
#include<cstring>
#include<cstdlib>
#include<list>
#include<map>
#include<queue>
#include<stack>
#include<vector>
using namespace std;
int n,k,m,ans;
int f[10005];
struct p{
    int st,to,w,idx;
    bool type;
};
vector<p> g,road;
bool cmp(p a,p b){
    if(a.w!=b.w)
        return a.w<b.w;
    return a.type>b.type;
}
bool cmp1(p a,p b){
    return a.idx<b.idx;
}
int find(int u){
    if(f[u]==u)return u;
    return f[u]=find(f[u]);
}
bool same(int u,int v){
    return find(u)==find(v);
}
bool unit(int u,int v){
    if(same(u,v))return false;
    f[find(u)]=v;
    return true;
}
void kruskal(){
    int edge=n-1;
    for(int i=0;i<g.size();i++){
        if(k>0&&!g[i].type){
            continue;
        }
        if(k==0){
            i=0;
            k--;
        }
        if(unit(g[i].st,g[i].to)){
            k-=g[i].type;
            edge--;
            ans=max(ans,g[i].w);
            road.push_back(g[i]);
        }
        if(!edge)break;
    }
}
int main(){
    cin>>n>>k>>m;
    for(int i=1;i<=n;i++)f[i]=i;
    for(int i=1,st,to,w1,w2;i<m;i++){
        cin>>st>>to>>w1>>w2;
        g.push_back({st,to,w1,i,1});
        g.push_back({st,to,w2,i,0});
    }
    sort(g.begin(),g.end(),cmp);
    kruskal();
    cout<<ans<<endl;
    sort(road.begin(),road.end(),cmp1);
    for(int i=0;i<road.size();i++){
        int type;
        if(road[i].type==1)type=1;
        else type=2;
        cout<<road[i].idx<<" "<<type<<endl;
    }
    return 0;
}

相關文章