zoukankan      html  css  js  c++  java
  • 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
    ") ; return 0 ; }
    	if(!query(upp)) { printf("-1
    ") ; return 0 ;  }
    	printf("%d
    ",n - 1) ;
    	for(int i = 1 ; i < n ; i ++) printf("%d ",Ans[i]) ;
    	return 0 ;
    }
    
  • 相关阅读:
    nodejs获取服务器数据到页面
    Struts 2
    JQuery
    JDBC
    Hiberbate
    EasyUi
    JavaScript
    利用 HashSet 去过滤元素是否重复
    HTML
    MySQL
  • 原文地址:https://www.cnblogs.com/beretty/p/9703066.html
Copyright © 2011-2022 走看看