次小生成树变体 HDU4081 Qin Shi Huang's National Road System

题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=24956

题意:给一些点和每个点上的权值。要求把所有路都连通。问取两个城市的人口和A,然后两个城市之间零代价连通,剩余路的长度为B,求A/B最大值。

思路:先最小生成树。

如果用Kruskal,则最后枚举小树上去掉哪条边,然后分别在边的两侧找出最大的人口,求和为A,而B为剩余路径长度。穷举得最大值。

如果Prim,穷举两个点,去掉他们形成的环上的最大边,而这个在初始加边的时候实现。靠,重新打的时候还是实现了很久,开了大量的数组来记录。加入新节点E,设原来已经得到的集合为W,则W中的点AE的环上最大边即为当前AE路径上的最大边。采用vector来存边,但还是要开一个mark数组记录到底是加了哪些边。

遗憾的是,len即总长度刚开始设为int致使无限出错。

还学了学低精度怎么转高精度,直接加就好。

输入时,double%lffloat%f;输出时,均为%f下次注意。

源码:

Kruskal:

#include <cstdio>

#include <cstring>

#include <string>

#include <cmath>

#include <queue>

#include <algorithm>

#include <iostream>

#include <map>

#include <vector>

using namespace std;

#define gmax(a,b) a>b?a:b

#define inf 99999999

#define LOCAL

int const MAXN = 1000+50;

int pa[MAXN],n,tot,use[MAXN];

double len;

//double dd[MAXN][MAXN];

struct D

{

    int x,y,peo;

    void init(int a,int b,int c){x=a;y=b;peo=c;}

}dot[MAXN];

struct E

{

    int s,e;

    double val;

    void init(int a,int b,double c){s=a;e=b;val=c;}

}edge[MAXN*MAXN/2],rest[MAXN];/**/

double dis(int i,int j)

{

    double s1 = ((dot[i].x-dot[j].x)*(dot[i].x-dot[j].x));

    double s2 = ((dot[i].y-dot[j].y)*(dot[i].y-dot[j].y));

    return sqrt(1.0*(s1+s2));

}

bool cmp(E a,E b)

{

    return a.val<b.val;

}

int fi(int a)

{

    if(a!=pa[a])    pa[a] =  fi(pa[a]);

    return pa[a];

}

vector<int>vv[MAXN];

void init()

{

    int x,y,p;

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

        scanf("%d%d%d",&x,&y,&p);

        dot[i].init(x,y,p);

        vv[i].clear();

    }

    tot = 0;

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

        for(int j=i+1; j<=n; j++){

            edge[tot].init(i,j,dis(i,j));

            tot++;

        }

    }

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

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

        pa[i] = i;

}

void Kruskal()

{

    len = 0;

    int ee = 0;

    sort(edge,edge+tot,cmp);

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

        int x = fi(edge[i].s);

        int y = fi(edge[i].e);

        if(x!=y){

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

            pa[x] = y;

            len += edge[i].val;

            rest[ee] = edge[i];

            ee++;

            int s = edge[i].s;int e = edge[i].e;

            vv[s].push_back(e);

            vv[e].push_back(s);

        }

        if(ee == n-1)

            break;

    }

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

}

int mmax;

void dfs(int a)

{

    use[a] = 1;

    mmax = max(mmax,dot[a].peo);

    for(int i=0; i<vv[a].size(); i++)

        if(use[vv[a][i]]==0){

            dfs(vv[a][i]);

        }

}

void solve()

{

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

    double ans=0;

//    printf("rest =\n");

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

//        printf("s = %d,e = %d,val = %f\n",rest[i].s,rest[i].e,rest[i].val);

//    }

//    printf("vv");

//    for(int i=1; i<=n; i++){

//        printf("for %d vv is ",i);

//        for(int j=0; j<vv[i].size(); j++)

//            printf("%d ",vv[i][j]);

//        printf("\n");

//    }

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

        double A=0,B;

        B = 1.0*(len - rest[i].val);

        int x = rest[i].s;  int y = rest[i].e;

        mmax = 0;memset(use,0,sizeof(use));use[x] = 1;dfs(y);

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

        A += mmax;mmax = 0;

        memset(use,0,sizeof(use));use[y] = 1;dfs(x);A+=mmax;

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

//        printf("for %d A = %f B = %f\n",i,A,B);

        ans = max(ans,(1.0*A)/B);

    }

    printf("%.2f\n",ans);

}

int main()

{

//    #ifdef LOCAL

//        freopen("data.txt","r",stdin);

//        freopen("data2.txt","w",stdout);

//    #endif // LOCAL

    int t;

    scanf("%d", &t);

    while(t--){

        scanf("%d",&n);

        init();

//        check();

        Kruskal();

        solve();

    }

    return 0;

}

Prim:

#include <cstdio>

#include <cmath>

#include <cstring>

#include <algorithm>

#include <iostream>

#include <queue>

using namespace std;

#define inf 99999999

#define LOCAL

int const MAXN = 1000+5;

double edge[MAXN][MAXN],maxcost[MAXN][MAXN],low[MAXN],use[MAXN],len;

int n,vis[MAXN],vv[MAXN][MAXN],mark[MAXN];

struct D

{

    int x,y,val;

    void init(int a,int b,int c){x=a;y=b;val=c;}

}dot[MAXN];

double dis(D a,D b)

{

    double s1 = pow(a.x-b.x,2);

    double s2 = pow(a.y-b.y,2);

    return sqrt(s1+s2);

}

vector<int>lin[MAXN];

void init()

{

    int x,y,val;

    len = 0;

    scanf("%d",&n);

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

        scanf("%d%d%d",&x,&y,&val);

        dot[i].init(x,y,val);

        lin[i].clear();

    }

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

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

            if(i==j)

                edge[i][j] = inf;

            else

                edge[i][j] = edge[j][i] = dis(dot[i],dot[j]);

//            if(i==1 && j==3){

//                printf("edge[1][3] = %f\n",edge[1][3]);

//            }

        }

    }

}

void dfs(int org,int st,double t)

{

    int i;

    vis[st] = 1;

    double t0;

    for(i=0; i<lin[st].size(); i++){

        if(vis[lin[st][i]]==0){

            t0 = max(t,edge[st][lin[st][i]]);

            maxcost[org][lin[st][i]] = maxcost[lin[st][i]][org] = t0;

//            printf("for org = %d,st = %d ,%d is %f\n",org,st,lin[st][i],t0);

            dfs(org,lin[st][i],t0);

        }

    }

}

void Prim()

{

    memset(maxcost,0,sizeof(maxcost));

    memset(use,0,sizeof(use));

    memset(vv,0,sizeof(vv));

    int st = 0;

    double t = edge[0][st];

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

        mark[i] = 0;

        low[i] = edge[0][i];

        if(low[i]<t){

            t = low[i];

            st = i;

        }

    }

    use[0] = 1;

    lin[0].push_back(st);

    lin[st].push_back(0);

    vv[st][0] = vv[0][st] = 1;

    while(use[st]==0){

        memset(vis,0,sizeof(vis));

        dfs(st,st,t);

//        printf("st = %d,t = %f\n",st,t);

//        printf("low = \n");

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

//            printf("%f ",low[i]);

//        printf("\n");

        use[st] = 1;

        len += t;

//        printf("len = %f\n",len);

        t = inf;

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

            if(low[i]>edge[st][i] && use[i]==0){

                low[i] = edge[st][i];

                mark[i] = st;

            }

        }

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

            if(low[i]<t && use[i]==0){

                t = low[i];

                st = i;

            }

        lin[st].push_back(mark[st]);

        lin[mark[st]].push_back(st);

        vv[mark[st]][st] = vv[st][mark[st]] = 1;

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

        }

//        printf("maxcost = \n");

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

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

//                printf("%f ",maxcost[i][j]);

//            printf("\n");

//        }

}

void solve()

{

    double ans = 0;

//    printf("len = %f\n",len);

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

        for(int j=i+1; j<n; j++){

            double A = dot[i].val + dot[j].val;

            double B;

            if(vv[i][j])    B = len - edge[i][j];

            else    B = len - maxcost[i][j];

//            printf("A = %f,B = %f\n",A,B);

            ans = max(ans, A/B);

        }

    }

    printf("%.2f\n",ans);

}

int main()

{

//    #ifdef LOCAL

//        freopen("data.txt","r",stdin);

//        freopen("data3.txt","w",stdout);

//    #endif // LOCAL

    int t;

    scanf("%d",&t);

    while(t--){

        init();

        Prim();

        solve();

    }

    return 0;

}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值