HDU 4081 Qin Shi Huang's National Road System

題目大意:

        現有t個測例(t ≤ 10),每個測例都會給出n個點的座標(2 < n ≤ 1,000),每個點的座標信息形式諸如"X Y P",表示點的座標爲(X, Y),點權值爲P,都爲整型,其中0 ≤ X, Y ≤ 1,000,0 < P < 100,000,現要求n - 1條邊將所有n個點都連通,並且將其中一條邊的權值變爲0,現要使變爲0的邊的兩點的權值之和比上其它邊權值之和最大,該如何構造這n - 1條以及如何挑選變爲0的邊才能是該比值最大,要求對於每個測例都輸出該最大值,保留兩位小數(邊長即爲兩點的歐幾里得距離)。

題目鏈接

註釋代碼:

/*                                  
 * Problem ID : HDU 4081 Qin Shi Huang's National Road System
 * Author     : Lirx.t.Una                                  
 * Language   : C++                      
 * Run Time   : 171 ms                                  
 * Run Memory : 18200 KB                                  
*/

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <queue>

//思路:
//先求MST使得n個點連通且邊數爲n - 1,並且使得總邊權儘可能小
//這也使得點權比邊權儘可能大
//然後在挑選邊變爲0測試ratio的大小,但是最小生成樹可能有多個
//本來邊(i, j)不在當前MST中,但是有可能在另一個MST中
//因此需要通過max_seg[i][j]換邊得到另一種最小生成樹
//但是g[i][j]並不一定等於max_seg[i][j],但是沒有關係
//因爲即使替換了也要將其邊權變爲0,就相當於將兩點合爲一點,因此沒有關係
//因此最後逐個檢查圖中的每條邊g[i][j],如果g[i][j]是當前MST中的點則非0邊權爲總邊權減去g[i][j]
//否則非0邊權就是總邊權減去max_seg[i][j]

//最大點數
#define    MAXN    1000

using namespace std;

struct    Point {//每個點的座標以及點權值

    int        x, y;
    int        w;

    friend istream &
    operator>>(istream &is, Point &p) {
    
        is >> p.x >> p.y >> p.w;
        return is;
    }

    int
    POW(int a) { return a * a; }

    double
    operator^(Point &oth) {
    
        return sqrt((double)( POW( x - oth.x ) + POW( y - oth.y ) ));
    }
};

struct    Node {//Prim堆優化中的結點

    int       u;
    double    d;

    Node(void) {}

    Node( int uu, double dd ) : u(uu), d(dd) {}

    bool
    operator<(const Node &oth)
    const {
    
        return d > oth.d;
    }
};

double        max_seg[MAXN + 1][MAXN + 1];
double        g[MAXN + 1][MAXN + 1];
double        d[MAXN + 1];

Point    p[MAXN + 1];//表示每個點

int        pre[MAXN + 1];

bool    vis[MAXN + 1];
bool    mst[MAXN + 1][MAXN + 1];

inline double
max( double a, double b ) {

    return a > b ? a : b;
}

double//返回最小生成樹的總邊權
prim(int n) {

    int        i;
    int        u, v;
    int        nv;

    double    ans;

    Node    node;

    priority_queue<Node>    heap;

    memset(vis, 0, sizeof(vis));
    memset(mst, 0, sizeof(mst));
    memset(max_seg, -1, sizeof(max_seg));

    vis[1] = true;
    for ( i = 2; i <= n; i++ ) {
    
        d[i]   = g[1][i];
        pre[i] = 1;

        heap.push(Node( i, d[i] ));
    }

    ans = 0.0;
    nv  = 1;
    while (true) {//完全圖必定有解,無需判斷
    
        while (true) {//必定有解
        
            node = heap.top();
            heap.pop();

            if ( !vis[ u = node.u ] ) {
            
                nv++;
                ans += node.d;

                mst[ pre[u] ][u] = true;
                mst[u][ pre[u] ] = true;

                for ( i = 1; i <= n; i++ )
                    if ( vis[i] ) {
                    
                        max_seg[i][u] = max( max_seg[i][ pre[u] ], node.d );
                        max_seg[u][i] = max_seg[i][u];
                    }

                vis[u] = true;

                break;
            }
        }

        if ( nv == n ) break;

        for ( v = 2; v <= n; v++ )
            if ( !vis[v] && g[u][v] < d[v] ) {
            
                d[v]   = g[u][v];
                pre[v] = u;

                heap.push(Node( v, d[v] ));
            }
    }

    return ans;
}

int
main() {

    int        t;
    int        n;

    int        i, j;

    double    B;//MST邊的總權值
    double    r;//最後的比例

    scanf("%d", &t);
    while ( t-- ) {
    
        scanf("%d", &n);

        for ( i = 1; i <= n; i++ ) cin >> p[i];
        for ( i = 1; i <= n; i++ )
            for ( j = i + 1; j <= n; j++ ) {
            
                g[i][j] = p[i] ^ p[j];
                g[j][i] = g[i][j];
            }

        r = -1.0;//初始化爲一個極小值
        B = prim(n);

        for ( i = 1; i <= n; i++ )
            for ( j = i + 1; j <= n; j++ )
                if ( mst[i][j] )//MST中的邊之間邊爲0試一下
                    r = max( r, ( p[i].w + p[j].w ) / ( B - g[i][j] ) );
                else//非MST中的邊g[i][j]替換max_seg[i][j]再變爲0試一下
                    r = max( r, ( p[i].w + p[j].w ) / ( B - max_seg[i][j] ) );

        printf("%.2lf\n", r);
    }        
	
    return 0;
}
無註釋代碼:

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <queue>

#define    MAXN    1000

using namespace std;

struct    Point {

    int        x, y;
    int        w;

    friend istream &
    operator>>(istream &is, Point &p) {
    
        is >> p.x >> p.y >> p.w;
        return is;
    }

    int
    POW(int a) { return a * a; }

    double
    operator^(Point &oth) {
    
        return sqrt((double)( POW( x - oth.x ) + POW( y - oth.y ) ));
    }
};

struct    Node {

    int        u;
    double    d;

    Node(void) {}

    Node( int uu, double dd ) : u(uu), d(dd) {}

    bool
    operator<(const Node &oth)
    const {
    
        return d > oth.d;
    }
};

double        max_seg[MAXN + 1][MAXN + 1];
double        g[MAXN + 1][MAXN + 1];
double        d[MAXN + 1];

Point    p[MAXN + 1];

int        pre[MAXN + 1];

bool    vis[MAXN + 1];
bool    mst[MAXN + 1][MAXN + 1];

inline double
max( double a, double b ) {

    return a > b ? a : b;
}

double
prim(int n) {

    int        i;
    int        u, v;
    int        nv;

    double    ans;

    Node    node;

    priority_queue<Node>    heap;

    memset(vis, 0, sizeof(vis));
    memset(mst, 0, sizeof(mst));
    memset(max_seg, -1, sizeof(max_seg));

    vis[1] = true;
    for ( i = 2; i <= n; i++ ) {
    
        d[i]   = g[1][i];
        pre[i] = 1;

        heap.push(Node( i, d[i] ));
    }

    ans = 0.0;
    nv    = 1;
    while (true) {
    
        while (true) {
        
            node = heap.top();
            heap.pop();

            if ( !vis[ u = node.u ] ) {
            
                nv++;
                ans += node.d;

                mst[ pre[u] ][u] = true;
                mst[u][ pre[u] ] = true;

                for ( i = 1; i <= n; i++ )
                    if ( vis[i] ) {
                    
                        max_seg[i][u] = max( max_seg[i][ pre[u] ], node.d );
                        max_seg[u][i] = max_seg[i][u];
                    }

                vis[u] = true;

                break;
            }
        }

        if ( nv == n ) break;

        for ( v = 2; v <= n; v++ )
            if ( !vis[v] && g[u][v] < d[v] ) {
            
                d[v]   = g[u][v];
                pre[v] = u;

                heap.push(Node( v, d[v] ));
            }
    }

    return ans;
}

int
main() {

    int        t;
    int        n;

    int        i, j;

    double    B;
    double    r;

    scanf("%d", &t);
    while ( t-- ) {
    
        scanf("%d", &n);

        for ( i = 1; i <= n; i++ ) cin >> p[i];
        for ( i = 1; i <= n; i++ )
            for ( j = i + 1; j <= n; j++ ) {
            
                g[i][j] = p[i] ^ p[j];
                g[j][i] = g[i][j];
            }

        r = -1.0;
        B = prim(n);

        for ( i = 1; i <= n; i++ )
            for ( j = i + 1; j <= n; j++ )
                if ( mst[i][j] ) 
                    r = max( r, ( p[i].w + p[j].w ) / ( B - g[i][j] ) );
                else
                    r = max( r, ( p[i].w + p[j].w ) / ( B - max_seg[i][j] ) );

        printf("%.2lf\n", r);
    }        

    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章