hdu4081 Qin Shi Huang's National Road System 次小生成树

  先发发牢骚:图论500题上说这题是最小生成树+DFS,网上搜题解也有人这么做。但是其实就是次小生成树。次小生成树完全当模版题。其中有一个小细节没注意,导致我几个小时一直在找错。有了模版要会用模版,然后慢慢融会贯通。我要走的路还长着啊。

  讲讲次小生成树的思想吧。首先,在prim算法中做一些改变,求出任意两点(u,v)路径之间的最大权值,并记录,记为maxe[u][v]。运行遍prim算法。枚举每一条边,如果该边是属于最小生成树的边,则ratio=(value(u) +value(v) ) /( ans-map[u][v] ),其中ans是最小生成树的权值之和。否则,ratio=(value(u) +value(v) ) /( ans-maxe[u][v] )。更新ratio的值,取最大值。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
const int N=1010,INF=0x3f3f3f3f;
int pre[N];
double dist[N],Map[N][N],maxe[N][N];
//向外延伸的最短边长,记录图信息,最长边
bool vis[N];//1表示点已经在树的,0表示点在树外
bool f[N][N];//存在边为1,用过为0
int n;
double Prim()
{
    int i,j,k;
    double Min,ans=0;
    memset(vis,0,sizeof(vis));
    memset(f,0,sizeof(f));
    memset(maxe,0,sizeof(maxe));
    for(i=2;i<=n;i++)
    {
        dist[i]=Map[1][i];
        pre[i]=1;
    }
    dist[1]=0;
    vis[1]=1;
    pre[1]=0;
    for(i=1;i<n;i++)
    {
        Min=INF;
        k=0;
        for(j=1;j<=n;j++)
        {
            if(!vis[j]&&dist[j]<Min)
            {
                Min=dist[j];
                k=j;
            }
        }
        //if(Min==INF) return -1;//G不连通
        vis[k]=1;
        ans+=Min;
        f[pre[k]][k] = f[k][pre[k]]=1;
        for(j=1;j<=n;j++)
        {
            if(vis[j]&&j!=k) maxe[k][j]=maxe[j][k]=max(maxe[j][pre[k]],dist[k]);
            if(!vis[j]&&dist[j]>Map[k][j])
            {
                dist[j]=Map[k][j];
                pre[j]=k;
            }
        }
    }
    return ans;
}
struct node
{
    double x,y,w;
}nd[N];
double Dis(double x,double y,double a,double b)
{
    return sqrt((a-x)*(a-x)+(b-y)*(b-y));
}
int main()
{
    //freopen("test.txt","r",stdin);
    int cas,i,j;
    scanf("%d",&cas);
    while(cas--)
    {
        scanf("%d",&n);
        for(i=1;i<=n;i++)
            Map[i][i]=0;
        for(i=1;i<=n;i++)
            scanf("%lf%lf%lf",&nd[i].x,&nd[i].y,&nd[i].w);
        for(i=1;i<=n;i++)
            for(j=1;j<i;j++)
                Map[i][j]=Map[j][i]=Dis(nd[i].x,nd[i].y,nd[j].x,nd[j].y);
        double ans=Prim(), rat=-1;
        for(i=1;i<=n;i++)
        {
            for(j=1;j<=n;j++)if(i!=j)
            {
                if(!f[i][j])
                    rat=max(rat,1.0*(nd[i].w+ nd[j].w)/(ans-maxe[i][j])) ;
                else
                    rat=max(rat,1.0*(nd[i].w+ nd[j].w)/(ans-Map[i][j]));
            }
        }
        printf("%0.2f\n",rat);
    }
    return 0;
}

hdu4081 Qin Shi Huang's National Road System 次小生成树

时间: 2024-11-25 06:50:03

hdu4081 Qin Shi Huang's National Road System 次小生成树的相关文章

hdu 4081 Qin Shi Huang&#39;s National Road System 次小生成树 算法

Qin Shi Huang's National Road System Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 4180    Accepted Submission(s): 1450 Problem Description During the Warring States Period of ancient China(4

HDU 4081 Qin Shi Huang&#39;s National Road System 次小生成树

给你n个城市 每个城市有一定数量的人 连接2个城市需要的花费是他们之间的距离 现在要建一颗最小生成树 可以免费建其中一条边 设A为免费的那条边连接的2个城市的人口之和 B为修建的最小生成树的花费 求最大的A/B 先求最小生成树 设总花费为totol 然后可以枚举免费的那条边 枚举边等于A确定 在这条在最小生成树里的情况下 求最小的B 如果这条边是最小生成树里的边 那么很容易求得B 拿totol减去这条边就行了 如果不是 那么把这条边加到最小生成树 会出现一个环 找到这个环最大的那条边剪掉 就是次

HDU 4081 Qin Shi Huang&#39;s National Road System 次小生成树变种

Qin Shi Huang's National Road System Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) [Problem Description] During the Warring States Period of ancient China(476 BC to 221 BC), there were seven kingdoms in China ---

HDU4081 Qin Shi Huang&#39;s National Road System【Kruska】【次小生成树】

Qin Shi Huang's National Road System Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 3979    Accepted Submission(s): 1372 Problem Description During the Warring States Period of ancient China(4

HDU4081 Qin Shi Huang&#39;s National Road System(次小生成树)

枚举作为magic road的边,然后求出A/B. A/B得在大概O(1)的时间复杂度求出,关键是B,B是包含magic road的最小生成树. 这么求得: 先在原图求MST,边总和记为s,顺便求出MST上任意两点路径上的最长边d[i][j]. 当(u,v)是magic road时, 如果它在原本的MST上,则B就等于s-原(u,v)的权,而原(u,v)的权其实就是d[u][v]: 如果它不在原本的MST上,则B就等于s-d[u][v]+0. 总之就是一个式子:B=s-d[u][v]. 于是,在

HDU4081 Qin Shi Huang&#39;s National Road System 【次小生成树】

Qin Shi Huang's National Road System Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 3395    Accepted Submission(s): 1189 Problem Description During the Warring States Period of ancient China(4

HDU4081 Qin Shi Huang&#39;s National Road System【prim最小生成树+枚举】

先求出最小生成树,然后枚举树上的边,对于每条边"分别"找出这条割边形成的两个块中点权最大的两个 1.由于结果是A/B,A的变化会引起B的变化,两个制约,无法直接贪心出最大的A/B,故要通过枚举 2.不管magic road要加在哪里,加的边是否是最小生成树上的边,都会产生环,我们都要选择一条边删掉 注意删掉的边必须是树的环上的边,为了使结果最大,即找出最大的边 3.可以枚举两点,找出边,也可以枚举边,找出点,我是用后者,感觉比较容易写也好理解 #include <cstdio&g

HDU-4081 Qin Shi Huang&#39;s National Road System(最小生成树)

今天比赛AC的一道最小生成树的题目 , 学到了不少东西 . 最小生成树的模板很简单,最简洁好写的还是lrj紫书上的代码 .利用并查集加速算法 . 该题的不同之处在于它选择任意一条路修成"魔法"道路 , 然后其他路的权值之和还要是最小的一棵次小生成树,并且求魔法道路两端点值之和除以其他路径长之和的最大值 . 显然该题的难点在于枚举两个端点之后怎么快速的求出次小生成树权值之和 .  枚举两个端点之后的复杂度已经是O(n^2),所以要想出一个快速的方法 . 受紫书上例题uva 1151 (传

HDU4081 Qin Shi Huang&#39;s National Road System

这个题还是比较好的,提供了一种求最小生成树不错的方法,但是,C++ TLE,G++  400+ms 1 #include <cmath> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 using namespace std; 6 const int maxn = 1005; 7 struct edge 8 { 9 int v,next; 10 double w; 11 }e