【HDU】4984 Goffi and Graph 最大生成树

来源:互联网 发布:淘宝刷手机单假聊流程 编辑:程序博客网 时间:2024/05/17 09:13

传送门:【HDU】4984 Goffi and Graph


题目分析:题目中的F( i , t )表示在t时刻编号为1的点到i的所有路径中的最小边的中值最大的边的值。很明显F( i , t )代表的边一定在最大生成树上(证:假设所有到i的路径的最小边都不在最大生成树上,则部分点不连通,这与所有点构成最大生成树想矛盾,所以至少有一条最小边在最大生成树上。又因为这是最大生成树,优先添加边权大的边,所以所有到i的路径的最小边中边权最大的边一定在最大生成树上,即F( i , t )一定在最大生成树上。得证!)。也就是说如果每个时刻的最大生成树都求出来以后,则最后积分式也就可以求了。

这里我们可以发现最大生成树的F( i , t ) 发生变化当且仅当直线相交时。如果某一段时间内并没有直线相交,则这个时间段中的所有F( i , t )的积分其实就是一个个梯形的面积。因此我们需要求出所有直线相交的时间点,两个相邻的时间点就是一个时间段,因为是一次函数,所以这时边权可以用两个时间点的中点来计算,很巧的是,因为边权*两个时间点之差恰好等于一个梯形的面积,所以只要得到此时间段内属于点i的最大的最小边的边权即可。而求点i在某个时间段内的最大的最小边可以用最大生成树+dfs来求出。


代码如下:


#include <cstdio>#include <cstring>#include <algorithm>using namespace std ; #define REP( i , a , b ) for ( int i = ( a ) ; i <  ( b ) ; ++ i )#define FOR( i , a , b ) for ( int i = ( a ) ; i <= ( b ) ; ++ i )#define REV( i , a , b ) for ( int i = ( a ) ; i >= ( b ) ; -- i )#define travel( e , H , u ) for ( Edge* e = H[u] ; e ; e = e -> next )#define CLR( a , x ) memset ( a , x , sizeof a )typedef long long LL ;const int MAXN = 55 ;const int MAXE = 205 ;const double INF = 1e10 ;const double eps = 1e-8 ;struct Edge {int v ;double c ;Edge* next ;} E[MAXE] , *H[MAXN] , *cur ;struct Line {int x , y , a , b ;double v ;void input () {scanf ( "%d%d%d%d" , &x , &y , &a , &b ) ;}bool operator < ( const Line& p ) const {return v > p.v ;}} L[MAXE] ;int n , m , t ;int p[MAXN] ;double f[MAXN] ;double a[10005] ;int cnt ;double st , ed , ans ;int sgn ( double x ) {return ( x > eps ) - ( x < -eps ) ;}void clear () {cur = E ;CLR ( H , 0 ) ; FOR ( i , 1 , n ) {p[i] = i ;f[i] = INF ;}}void addedge ( int u , int v , double c ) {cur -> v = v ;cur -> c = c ;cur -> next = H[u] ;H[u] = cur ++ ;}int find ( int x ) {return p[x] == x ? x : ( p[x] = find ( p[x] ) ) ;}void kruskal () {sort ( L , L + m ) ;int cnt = 1 ;REP ( i , 0 , m ) {int x = find ( L[i].x ) ;int y = find ( L[i].y ) ;if ( x != y ) {p[x] = y ;addedge ( L[i].x , L[i].y , L[i].v ) ;addedge ( L[i].y , L[i].x , L[i].v ) ;if ( ++ cnt == n ) break ;}}}void dfs ( int u , int fa ) {travel ( e , H , u ) {int v = e -> v ;if ( v == fa ) continue ;f[v] = min ( f[u] , e -> c ) ;dfs ( v , u ) ;}}int unique ( int n ) {int cnt = 1 ;sort ( a + 1 , a + n + 1 ) ;FOR ( i , 2 , n ) if ( sgn ( a[i] - a[cnt] ) ) a[++ cnt] = a[i] ;return cnt ;}void solve () {ans = 0 ;cnt = 0 ;scanf ( "%d%d%d" , &n , &m , &t ) ;REP ( i , 0 , m ) {L[i].input () ;REP ( j , 0 , i ) {if ( L[i].b == L[j].b ) continue ;a[++ cnt] = ( double ) ( L[i].a - L[j].a ) / ( L[j].b - L[i].b ) ;}}a[++ cnt] = t ;cnt = unique ( cnt ) ;st = 0 ;FOR ( i , 1 , cnt ) {if ( a[i] < 0 ) continue ;if ( a[i] > t ) break ;ed = a[i] ;double mid = ( st + ed ) / 2 ;REP ( j , 0 , m ) L[j].v = L[j].a + L[j].b * mid ;clear () ;kruskal () ;dfs ( 1 , 0 ) ;FOR ( j , 2 , n ) ans += f[j] * ( ed - st ) ;st = ed ;}printf ( "%.3f\n" , ans / t ) ;}int main () {int T ;scanf ( "%d" , &T ) ;while ( T -- ) solve () ;return 0 ;}


0 0
原创粉丝点击