[BZOJ1614]-[Usaco2007 Jan]Telephone Lines-二分答案+最短路

说在前面

并没有什么想说的,但是要保持格式=w=


题目

BZOJ1614传送门

题目大意

给出一个 n 个点 m 条边的无向图,再给出一个常数 K
定义一条路径的花费为:组成这条路径的边权的最大值
现在需要选择一条从 1 n 的路径,可以使路径上任意 K 条边边权变成 0 ,问最小花费
范围: 0 K < n 1000 m 10000 ,边权 [ 1 , 10 6 ]

输入输出格式

输入格式:
第一行三个数字 n , m , K ,含义如题
接下来 m 行,每行三个整数 u , v , w 描述一条边

输出格式:
输出一个整数表示答案
若无法连通,输出-1


解法

显然的二分答案
先建个图,把所有边的长度设1,跑一遍最短路,确认无解或者答案为0的情况

二分答案的时候,把边权大于当前二分值的,在图中的长度设为1,否则0,然后check最短路是否不超过K即可


下面是代码

#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std ;

int N , P , K , head[1005] , tp ;
int len[20005] ;
struct Path{
    int pre , to , len ;
} p[20005] ;

template < typename T > void smin( T &x , T y ){ if( x > y ) x = y ; }
template < typename T > void smax( T &x , T y ){ if( x < y ) x = y ; }

void In( int t1 , int t2 ){
    p[++tp] = ( Path ){ head[t1] , t2 , 1 } ; head[t1] = tp ;
    p[++tp] = ( Path ){ head[t2] , t1 , 1 } ; head[t2] = tp ;
}

int dis[1005] ;
bool inq[1005] ; queue<int> que ;
int Spfa(){
    memset( dis , 0x3f , sizeof( dis ) ) ;
    dis[1] = 0 ; que.push( 1 ) , inq[1] = true ;
    while( !que.empty() ){
        int u = que.front() ;
        que.pop() , inq[u] = false ;
        for( int i = head[u] ; i ; i = p[i].pre ){
            int v = p[i].to ;
            if( dis[v] > dis[u] + p[i].len ){
                dis[v] = dis[u] + p[i].len ;
                if( !inq[v] ) que.push( v ) , inq[v] = true ;
            }
        }
    } return dis[N] ;
}

void solve(){
    int dist = Spfa() , lf = 0x3f3f3f3f , rg = 0 , ans ;
    if( dist == 0x3f3f3f3f ) puts( "-1" ) , exit( 0 ) ;
    if( dist <= K ) puts( "0" ) , exit( 0 ) ;
    for( int i = 1 ; i <= tp ; i ++ )
        smin( lf , len[i] ) , smax( rg , len[i] ) ;
    while( lf <= rg ){
        int mid = ( lf + rg ) >> 1 ;
        for( int i = 1 ; i <= tp ; i ++ )
            p[i].len = ( len[i] > mid ) ;
        if( ( dist = Spfa() ) <= K )
            ans = mid , rg = mid - 1 ;
        else lf = mid + 1 ;
    } printf( "%d" , ans ) ;
}

int main(){
    scanf( "%d%d%d" , &N , &P , &K ) ;
    for( int i = 1 , u , v , w ; i <= P ; i ++ ){
        scanf( "%d%d%d" , &u , &v , &w ) ;
        In( u , v ) ; len[tp] = len[tp-1] = w ;
    } solve() ;
}

猜你喜欢

转载自blog.csdn.net/izumi_hanako/article/details/80369466