CF125E MST Company

题意翻译

求一种特殊的最小生成树。给定一个有n个节点和m条边的图,找出一个生成树满足从根节点1直接连向其余节点的边要恰好是k条,在此条件下生成树的权值和最小。

输入输出样例

输入样例#1:

4 5 2
1 2 1
2 3 1
3 4 1
1 3 3
1 4 2

输出样例#1:

3
1 5 2


话说我一开始以为和免费道路那题一样直接上3遍\(kruskal\)但一直WA14

然后就去看了题解

发现正解是二分 + \(kruskal\)

具体思路就是每次给起点为1的边二分一个值

让所有的起点为1的边都减去这个值

因为\(kruskal\)要先按照边权排序

所以减去二分的值以后边的排名就会发生改变

然后判断是否能选到k条起点为1的边

然后注意判断无解的情况

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
const int M = 200005 ;
using namespace std ;
inline int read() {
    char c = getchar() ; int x = 0 , w = 1 ;
    while(c>'9'||c<'0') { if(c=='-') w = -1 ; c = getchar() ; }
    while(c>='0'&&c<='9') { x = x*10+c-'0' ; c = getchar() ; }
    return x*w ;
} 

int n , m , k ;
int Num1 , upp , f[M] , tot , Num , Ans[M] ;
struct E {
    int from , to , dis , Id ;
} edge[M] ;
inline bool operator < (E a , E b) { return a.dis == b.dis ? a.from < b.from : a.dis < b.dis ; }
int find(int x) { if(f[x] != x) f[x] = find(f[x]) ; return f[x] ;  }
inline int chk(int mid) {
    for(int i = 1 ; i <= m ; i ++) 
        if(edge[i].from == 1) 
            edge[i].dis += mid ;
    for(int i = 1 ; i <= n ; i ++) f[i] = i ;
    tot = 0 , Num = 0 ;
    sort(edge + 1 , edge + m + 1) ;
    for(int i = 1 , u , v , x , y ; i <= m ; i ++) {
        u = edge[i].from , v = edge[i].to ;
        x = find(u) , y = find(v) ;
        if(x == y) continue ;
        f[y] = x ; ++tot ; if(u == 1) ++Num ;
        if(tot == n - 1) break ;
    }
    for(int i = 1 ; i <= m ; i ++)
        if(edge[i].from == 1)
            edge[i].dis -= mid ;
    return Num ;
}
inline bool query(int mid) {
    for(int i = 1 ; i <= m ; i ++)
        if(edge[i].from == 1)
            edge[i].dis += mid ;
    for(int i = 1 ; i <= n ; i ++) f[i] = i ;
    tot = 0 , Num = 0 ;
    sort(edge + 1 , edge + m + 1) ;
    for(int i = 1 , u , v , x , y ; i <= m ; i ++) {
        u = edge[i].from , v = edge[i].to ;
        x = find(u) , y = find(v) ;
        if(x == y) continue ;
        if(u == 1 && Num == k) continue ;
        f[y] = x ; if(u == 1) ++Num ;
        Ans[++tot] = edge[i].Id ;
        if(tot == n - 1) break ;
    }
    if(Num < k || tot != n - 1) return false ;
    return true ; 
}
int main() {
    n = read() ; m = read() ; k = read() ;
    for(int i = 1 ; i <= m ; i ++) {
        edge[i].from = read() , edge[i].to = read() ;
        edge[i].dis = read() ; edge[i].Id = i ;
        if(edge[i].from > edge[i].to) swap(edge[i].from , edge[i].to) ;
        if(edge[i].from == 1) ++Num1 ;
    }
    int l = -100001 , r = 100001 ;
    while(l <= r) {
        int mid = (l + r) >> 1 ;
        if(chk(mid) >= k) l = mid + 1 , upp = mid ;
        else r = mid - 1 ;
    }
    if(upp < -100001) { printf("-1\n") ; return 0 ; }
    if(!query(upp)) { printf("-1\n") ; return 0 ;  }
    printf("%d\n",n - 1) ;
    for(int i = 1 ; i < n ; i ++) printf("%d ",Ans[i]) ;
    return 0 ;
}

猜你喜欢

转载自www.cnblogs.com/beretty/p/9703066.html
MST
今日推荐