HDU4756+Prim

题意简单:去掉最小生成树的某一条边并补上一条,求MaxVal

思路:贪心(借鉴Yamidie的思路。。。)

分别求出最小生成树和次最小生成树,再在这两棵树上求最小生成树

#include<stdio.h>

#include<string.h>

#include<stdlib.h>

#include<algorithm>

#include<math.h>

using namespace std;

const int maxn = 1015;

const int maxm = maxn*maxn;

const int inf1 = 0x3f3f3f3f;

const double inf2 = 9999999999;



struct Point {

    double x,y;

}pnt[ maxn ];

struct Edge{

    int u,v;

    double val;

    int id;

}edge[ maxn<<1 ];

int cnt_edge;

double mat[ maxn ][ maxn ];

double dis[ maxn ];

bool vis[ maxn ];

int pre[ maxn ];



double LenPrim1;

double LenPrim2;



int fa[ maxn ],rank[ maxn ];



int find( int x ){

    if( x==fa[x] ) return x;

    else return fa[ x ] = find( fa[x] );

}



void init( int n ){

    for( int i=0;i<n;i++ ){

        fa[ i ] = i;

        rank[ i ] = 1;

    }

    return ;

} 

 

double dist( int i,int j ){

    return sqrt( (pnt[i].x-pnt[j].x)*(pnt[i].x-pnt[j].x)+(pnt[i].y-pnt[j].y)*(pnt[i].y-pnt[j].y) );

} 



int cmp( Edge a,Edge b ){

    return a.val<b.val;

}    



void GetMap( int n ){

    for( int i=0;i<n;i++ )

        for( int j=0;j<n;j++ ){

            mat[i][j] = dist( i,j );

            //printf("mat[%d][%d]=%.3lf\n",i,j,mat[i][j]);

        }

    return ;

}



double prim( int n,int Belong ){

    for( int i=0;i<n;i++ ){

        dis[ i ] = mat[0][i];

        vis[ i ] = false;

        pre[ i ] = 0;

    }

    vis[0] = true;

    //if( Belong==2 ){

    //    for( int i=0;i<n;i++ )for( int j=0;j<n;j++ ) 

            //printf("mat[%d][%d]=%.3lf\n",i,j,mat[i][j]);

    //}

    double ans = 0;

    for( int i=0;i<n;i++ ){

        int id = -1;

        double M = inf2;

        for( int j=0;j<n;j++ ){

            if( !vis[j] && M>dis[j] ){

                M = dis[j];

                id = j;

            }

        }

        if( id==-1 ) break;

        vis[ id ] = true;

        ans += M;

        edge[ cnt_edge ].u = pre[ id ];

        edge[ cnt_edge ].v = id;

        edge[ cnt_edge ].id = Belong;

        edge[ cnt_edge ].val = mat[ id ][ pre[id] ];

        //printf("u = %d,v = %d\n",edge[cnt_edge].u,edge[cnt_edge].v);

        cnt_edge ++ ;

        for( int j=0;j<n;j++ ){

            if( !vis[j] && dis[j]>mat[id][j] ){

                dis[j] = mat[id][j];

                pre[ j ] = id;

            }

        }

    }

    return ans;

}    



void Deal( int n ){

    for( int i=0;i<cnt_edge;i++ ){

        mat[ edge[i].u ][ edge[i].v ] = inf2;

        mat[ edge[i].v ][ edge[i].u ] = inf2;

    }

}



double Kruskal( int n,int id ){

    double ans = 0;

    init( n );

    int cnt = 0;

    for( int i=0;i<cnt_edge;i++ ){

        if( i==id ) continue;

        int fx = find( edge[i].u );

        int fy = find( edge[i].v );

        if( fx!=fy ){

            if( rank[ fx ]<rank[ fy ] ){

                rank[ fy ] += rank[ fx ];

                fa[ fx ] = fy;

            }

            else {

                rank[ fx ] += rank[ fy ];

                fa[ fy ] = fx;

            }

            cnt ++ ;

            ans += edge[i].val;

            if( cnt==n-1 ) break;

        }

       }

       return ans;

}



int main(){

    int T;

    scanf("%d",&T);

    while( T-- ){

        int n;

        double k;

        scanf("%d%lf",&n,&k);

        for( int i=0;i<n;i++ )

            scanf("%lf%lf",&pnt[i].x,&pnt[i].y);

        GetMap( n );

        cnt_edge = 0;

        LenPrim1 = prim( n,1 );

        Deal( n );

        LenPrim2 = prim( n,2 );

        double ans = LenPrim1;

        double temp_ans = 0;

        sort( edge,edge+cnt_edge,cmp );

        //printf("cnt_edge = %d\n",cnt_edge);

        for( int i=0;i<cnt_edge;i++ ){

            if( edge[i].id==1 && edge[i].u!=0 && edge[i].v!=0 ){

                temp_ans = Kruskal( n,i );

                if( temp_ans>ans )

                    ans = temp_ans;

            }

        }

        printf("%.2lf\n",ans*k);

    }

    return 0;

}


 

 

你可能感兴趣的:(Prim)