HDU - 4081(次小生成树)

题目网址:点击打开链接

这个wa了一天的题,,,总算是知道错哪了;

这个题目的要求是找两点之间建立一条边,然后这两个点的人口数为A,B为除去这两个点之间的距离,所有点相连通的其他路的总长;

因而转化为一个次小生成树的问题,先生成一个最小生成树,然后开始删边,删一条边之后会发现,分成的两个集合中任意两个点相连,所有的点就又是相互连通的了;

这个题目由于A/B的值未知,所以每两个点都需要考虑进去,想要在任意两个点之间建路,然后B希望最小,就是从两个点之间相连的路上寻找一个最长的边删掉,然后再将这两个点连通起来,又是一个连通图;

所以这个问题的核心就在于,寻找每两个点连接路上的最大路长;

例如1——————2————3——4   

                                              |

                                             6

如果希望在1-6之间建路的话,应该删掉的边是1-2他最长,然后连接1-6,又是一个树;


行了该上代码了

#include <iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<vector>
#include<cmath>
#include<cstdio>

using namespace std;
const int maxn=1000+5;
struct node
{
    int x,y;
};
struct ege
{
    int e,v;
    double w;
    ege(int ee=0,int vv=0,double ww=0)
    {
        e=ee;v=vv;w=ww;
    }
    bool operator<(const ege& s)const
    {
        return w<s.w;
    }
};
ege eg[maxn*maxn+5];
int p[maxn];

int pro[maxn];
int n,V,t;
node s[maxn];
double dis(int x,int y)
{
    return sqrt((double)(s[x].x-s[y].x)*(s[x].x-s[y].x)*1.0+(s[x].y-s[y].y)*(s[x].y-s[y].y)*1.0);
}
void inint(int n)
{
    for(int i=0;i<=n;i++)
        pro[i]=i;
}
int find(int x)
{
    if(x==pro[x])
        return x;
    else
        return pro[x]=find(pro[x]);

}
void uion(int x,int y)
{
    int xx=find(x);
    int yy=find(y);
    if(xx==yy)
        return ;
    else
        pro[xx]=yy;
}
int same(int x,int y)
{
    if(find(x)==find(y))
        return 1;
    else
        return 0;
}

vector <ege> e2[maxn];
double kur()
{
    inint(n);
   double res=0;
    int numm=0;
    sort(eg,eg+V);
    for(int i=0;i<V;i++)
    {
        ege ee=eg[i];
        if(!same(ee.e,ee.v))
        {   numm++;
            uion(ee.e,ee.v);
            res+=ee.w;
            e2[ee.e].push_back(ee);
            e2[ee.v].push_back(ege(ee.v,ee.e,ee.w));//这里之前不小心写错了
            if(numm==n-1)
                break;
        }
    }
    return res;
}
int cur[maxn];
int vis[maxn];
double e[maxn][maxn];
int num;
void dfs(int c)
{
    vis[c]=1;
    cur[num]=c;
    num++;
    for(int i=0;i<e2[c].size();i++)
    {
        int v=e2[c][i].v;
        double w=e2[c][i].w;
        if(!vis[v])
        {//cout<<w<<endl;
           //vis[v]=1;
            for(int j=0;j<num;j++)
            {
                e[v][cur[j]]=max(w,e[cur[j]][c]);
                e[cur[j]][v]=max(w,e[cur[j]][c]); //这就是我说的那个核心部分了
                      // 要注意的是,1-6 之间的最大距离应该在1-3和3-6之间产生,所以是e[6][1]=max(e[3][6]],e[1][3]);
            }
            dfs(v);
        }
    }
}

int main()
{
    cin>>t;
    while(t--)
    {
        cin>>n;
        for(int i=0;i<n;i++)
        {
            cin>>s[i].x>>s[i].y>>p[i];
        }
        V=0;
        memset(eg,0,sizeof(eg));
        for(int i=0;i<n;i++)
          for(int j=i+1;j<n;j++)
         {
            eg[V]=ege{i,j,dis(i,j)};
          //  cout<<dis(i,j)<<endl;;
            V++;
        }
        for(int i=0;i<n;i++)
            e2[i].clear();
        double res= kur();
       // cout<<res<<endl;
        num = 0;
        memset(vis,0,sizeof(vis));
        memset(e,0,sizeof(e));
        memset(cur,0,sizeof(cur));
        dfs(0);
        double maxx = 0;
        for(int i = 0;i < n; i++)
            for(int j = i + 1;j < n; j++)
           {
              //cout<<e[i][j]<<" ";
              //cout<<"  p="<<p[i]+p[j]<<endl;
              double ab = (double)(p[i]+p[j])/(res-e[i][j]);
              if(ab>maxx)
                 maxx=ab;
                //cout<<maxx<<endl;
           }
        printf("%.2f\n",maxx);
    }
 //   cout << "Hello world!" << endl;
    return 0;
}

总算是不在wa了,很多东西不要简单的以为自己会了,真让你自己动手的时候才显示出真章,年轻人好好努力吧,要知道,下一个最小生成树,你可能还是不会;

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值