程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> hdu 4081 Qin Shi Huangs National Road System (最小生成樹變形 兩種解法

hdu 4081 Qin Shi Huangs National Road System (最小生成樹變形 兩種解法

編輯:C++入門知識

Qin Shi Huang's National Road System Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2027    Accepted Submission(s): 741     Problem Description During the Warring States Period of ancient China(476 BC to 221 BC), there were seven kingdoms in China ---- they were Qi, Chu, Yan, Han, Zhao, Wei and Qin. Ying Zheng was the king of the kingdom Qin. Through 9 years of wars, he finally conquered all six other kingdoms and became the first emperor of a unified China in 221 BC. That was Qin dynasty ---- the first imperial dynasty of China(not to be confused with the Qing Dynasty, the last dynasty of China). So Ying Zheng named himself "Qin Shi Huang" because "Shi Huang" means "the first emperor" in Chinese.     Qin Shi Huang undertook gigantic projects, including the first version of the Great Wall of China, the now famous city-sized mausoleum guarded by a life-sized Terracotta Army, and a massive national road system. There is a story about the road system: There were n cities in China and Qin Shi Huang wanted them all be connected by n-1 roads, in order that he could go to every city from the capital city Xianyang. Although Qin Shi Huang was a tyrant, he wanted the total length of all roads to be minimum,so that the road system may not cost too many people's life. A daoshi (some kind of monk) named Xu Fu told Qin Shi Huang that he could build a road by magic and that magic road would cost no money and no labor. But Xu Fu could only build ONE magic road for Qin Shi Huang. So Qin Shi Huang had to decide where to build the magic road. Qin Shi Huang wanted the total length of all none magic roads to be as small as possible, but Xu Fu wanted the magic road to benefit as many people as possible ---- So Qin Shi Huang decided that the value of A/B (the ratio of A to B) must be the maximum, which A is the total population of the two cites connected by the magic road, and B is the total length of none magic roads. Would you help Qin Shi Huang? A city can be considered as a point, and a road can be considered as a line segment connecting two points.     Input The first line contains an integer t meaning that there are t test cases(t <= 10). For each test case: The first line is an integer n meaning that there are n cities(2 < n <= 1000). Then n lines follow. Each line contains three integers X, Y and P ( 0 <= X, Y <= 1000, 0 < P < 100000). (X, Y) is the coordinate of a city and P is the population of that city. It is guaranteed that each city has a distinct location.     Output For each test case, print a line indicating the above mentioned maximum ratio A/B. The result should be rounded to 2 digits after decimal point.     Sample Input 2 4 1 1 20 1 2 30 200 2 80 200 1 100 3 1 1 20 1 2 30 2 2 40     Sample Output 65.00 70.00     Source 2011 Asia Beijing Regional Contest     思路1: 枚舉a,保證每種情況b最小 先用Prim算最小生成樹,算的時候統計maxcost[u][v](最小生成樹上u到v的唯一路徑上的最大邊的值),然後二重循環枚舉a(即枚舉magic road),這樣最小生成樹會形成一個回路,刪除maxcost[u][v]就夠了(對每一種a保證了b最小)。   代碼:  

#include <cstdio>  
#include <cmath>  
#include <cstring>  
#include <vector>  
#include <algorithm>  
#define maxn 1005  
#define INF 0x3f3f3f3f  
using namespace std ;  
  
int n,m;  
bool vis[maxn];  
int pre[maxn];  
double sum,ans;  
double dist[maxn];  
double city[maxn][maxn],dd[maxn][maxn];  
vector<int>v;  
struct Node  
{  
    int x,y,p;  
}pp[maxn];  
  
void init()  
{  
    int i,j;  
    v.clear();  
    for(i=1;i<=n;i++)  
    {  
        dist[i]=INF;  
        for(j=1;j<=n;j++)  
        {  
            city[i][j]=INF;  
        }  
    }  
    memset(vis,0,sizeof(vis));  
    memset(dd,0,sizeof(dd));  
}  
double caldist(int k1,int k2)  
{  
    double xx,yy;  
    xx=pp[k1].x-pp[k2].x;  
    yy=pp[k1].y-pp[k2].y;  
    return sqrt(xx*xx+yy*yy);  
}  
void presolve()  
{  
    int i,j;  
    for(i=1;i<=n;i++)  
    {  
        for(j=i+1;j<=n;j++)  
        {  
            city[i][j]=city[j][i]=caldist(i,j);  
        }  
    }  
}  
void prim()  
{  
    int i,j,k,sz,now=1;  
    double mi;  
    sum=0;  
    vis[1]=1;  
    dist[1]=0;  
    v.push_back(1);  
    for(i=1;i<n;i++)  
    {  
        for(j=1;j<=n;j++)  
        {  
            if(!vis[j]&&city[now][j]<dist[j])  
                pre[j]=now,dist[j]=city[now][j];  
        }  
        mi=INF;  
        for(j=1;j<=n;j++)  
        {  
            if(!vis[j]&&dist[j]<mi)  
            {  
                mi=dist[j];  
                k=j;  
            }  
        }  
        sum+=dist[k];  
        now=k;  
        vis[k]=1;  
        sz=v.size();  
        for(j=0;j<sz;j++)  
        {  
            dd[v[j]][k]=dd[k][v[j]]=max(dd[v[j]][pre[k]],dist[k]);  
        }  
        v.push_back(k);  
    }  
}  
void solve()  
{  
    int i,j;  
    double a,b;  
    ans=0;  
    for(i=1;i<=n;i++)  
    {  
        for(j=i+1;j<=n;j++)  
        {  
            a=pp[i].p+pp[j].p;  
            b=sum-dd[i][j];  
            if(ans<a/b) ans=a/b;  
        }  
    }  
}  
int main()  
{  
    int i,j,t;  
    scanf("%d",&t);  
    while(t--)  
    {  
        scanf("%d",&n);  
        init();  
        for(i=1;i<=n;i++)  
        {  
            scanf("%d%d%d",&pp[i].x,&pp[i].y,&pp[i].p);  
        }  
        presolve();  
        prim();  
        solve();  
        printf("%.2f\n",ans);  
    }  
    return 0;  
}  

 

    思路2: 枚舉b,每種情況保證a最大。 先用Prim求出最小生成樹,求的同時構圖,然後依次刪除最小生成樹的每一條邊,刪除一條邊後會形成兩顆樹,而magic road肯定1.要把兩棵樹連起來。2.保證a最大。所以只需要分別找到兩棵樹中的最大的人口數就夠了。這個可以在圖上用dfs實現。   感想: 這個思路我比賽時想到了,沒想到構圖,感覺找到兩棵樹中的最大的人口數不好處理,就放棄了這個思路,╮(╯▽╰)╭,說多了都是淚,其實還是題做少了,算法學死了。。。   代碼:  
#include <cstdio>  
#include <cmath>  
#include <cstring>  
#include <algorithm>  
#define maxn 1005  
#define INF 0x3f3f3f3f  
using namespace std ;  
  
int n,m,cnt,nu,nv,maxp;  
bool vis[maxn];  
int pre[maxn];  
double sum,ans;  
double dist[maxn];  
double city[maxn][maxn],dd[maxn][maxn];  
struct Node  
{  
    int x,y,p;  
}pp[maxn];  
int pt[maxn];  
struct node  
{  
    int v,next;  
}edge[maxn<<1];  
struct Tnode  
{  
    int u,v;  
    double cost;  
}mst[maxn];  
  
void init()  
{  
    int i,j;  
    for(i=1;i<=n;i++)  
    {  
        dist[i]=INF;  
        for(j=1;j<=n;j++)  
        {  
            city[i][j]=INF;  
        }  
    }  
    cnt=0;  
    memset(pt,0,sizeof(pt));  
    memset(vis,0,sizeof(vis));  
}  
double caldist(int k1,int k2)  
{  
    double xx,yy;  
    xx=pp[k1].x-pp[k2].x;  
    yy=pp[k1].y-pp[k2].y;  
    return sqrt(xx*xx+yy*yy);  
}  
void presolve()  
{  
    int i,j;  
    for(i=1;i<=n;i++)  
    {  
        for(j=i+1;j<=n;j++)  
        {  
            city[i][j]=city[j][i]=caldist(i,j);  
        }  
    }  
}  
void addedge(int u,int v)  
{  
    cnt++;  
    edge[cnt].v=v;  
    edge[cnt].next=pt[u];  
    pt[u]=cnt;  
}  
void prim()  
{  
    int i,j,k,sz,now=1;  
    double mi;  
    sum=0;  
    vis[1]=1;  
    dist[1]=0;  
    for(i=1;i<n;i++)  
    {  
        for(j=1;j<=n;j++)  
        {  
            if(!vis[j]&&city[now][j]<dist[j])  
                pre[j]=now,dist[j]=city[now][j];  
        }  
        mi=INF;  
        for(j=1;j<=n;j++)  
        {  
            if(!vis[j]&&dist[j]<mi)  
            {  
                mi=dist[j];  
                k=j;  
            }  
        }  
        mst[i].u=pre[k];  
        mst[i].v=k;  
        mst[i].cost=dist[k];  
        addedge(k,pre[k]);  
        addedge(pre[k],k);  
        sum+=dist[k];  
        now=k;  
        vis[k]=1;  
    }  
}  
void dfs(int pos)  
{  
    if(maxp<pp[pos].p) maxp=pp[pos].p;  
    int i,j,u;  
    for(i=pt[pos];i;i=edge[i].next)  
    {  
        u=edge[i].v;  
        if(pos==nu&&u==nv||pos==nv&&u==nu) continue ;  
        if(!vis[u])  
        {  
            vis[u]=1;  
            dfs(u);  
        }  
    }  
}  
void solve()   // 依次去掉最小生成樹中的邊變成兩棵樹 找兩棵樹中的最大p1、p2  
{  
    int i,j;  
    double a,b;  
    ans=0;  
    for(i=1;i<n;i++)  
    {  
        nu=mst[i].u;  
        nv=mst[i].v;  
        a=0;  
        maxp=0;  
        memset(vis,0,sizeof(vis));  
        dfs(1);  
        a+=maxp;  
        for(j=2;j<=n;j++)  
        {  
            if(!vis[j])  
            {  
                vis[j]=1;  
                maxp=0;  
                dfs(j);  
                a+=maxp;  
                break ;  
            }  
        }  
        b=sum-mst[i].cost;  
        if(ans<a/b) ans=a/b;  
    }  
}  
int main()  
{  
    int i,j,t;  
    scanf("%d",&t);  
    while(t--)  
    {  
        scanf("%d",&n);  
        init();  
        for(i=1;i<=n;i++)  
        {  
            scanf("%d%d%d",&pp[i].x,&pp[i].y,&pp[i].p);  
        }  
        presolve();  
        prim();  
        solve();  
        printf("%.2f\n",ans);  
    }  
    return 0;  
}  

 


  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved