HDOJ 4081

来源:互联网 发布:微信钱包表结构 mysql 编辑:程序博客网 时间:2024/04/25 14:16

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4081

-————————————————————————————————————————————————

题目关键字: memset 、 prim

————————————————————————————————————————————————

题目描述:

无向完全图,有n个点,每个点有个点权。作一生成树,生成树上的一个边的边权可以忽略,若被忽略边权的边的两个端点的点权和为A,生成树剩余边的边权和为B,求一生成树使 A/B 最大,打印这个最大的比值。

————————————————————————————————————————————————

题目思路;

先求作一最小生成树。再扫描各边,若边在最小生成树中,则直接减掉这个边即可。若边不在最小生成树中,则减去加上该边构成的环中边权最大的。

在用prim求作最小生成树的过程中,用 dp[i][j]维护一个从i到j的最大边权值 :

dp[u][j] = dp[j][u] = max(dp[j][k],min)   (**)

u是新加入的节点,k是u的前继。min是新加入的边。

所以不需要分类讨论了,当某个边 i j 属于最小生成树时,由于 dp[i][i]为0,所以dp[i][j]自然为 i与j的距离。

—————————————————————————————————————————————————

题目细节:

1、用prim算法较好,这样可以及时维护dp。(第一次写prim,莫敲。。再次感谢某位同学)

2、稠密图还是用邻接矩阵更省事儿。

——————————————————————————————————————————————————

源代码:

#include<cstdio>#include<cstring>#include<algorithm>#include<vector>#include<math.h>using namespace std;#define MAX 2100000000#define maxn 1010#define max(a,b) ((a)<(b)?(b):(a))double edge[maxn][maxn];double p[maxn];double x[maxn];double y[maxn];double dis[maxn];int vis[maxn];int pre[maxn];double dp[maxn][maxn];int n = 0;double sum = 0;double d(double x1,double x2,double y1,double y2){    return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));}void prim(){    int i = 0,j = 0;    memset(vis,0,sizeof(vis));    sum = 0;    for (int i=1;i<=n;i++)    {        pre[i]=i;        dis[i]=MAX;    }    dis[1]=0;    memset(dp,0,sizeof(dp));int u;for (i = 1;i<=n;i++){    doublemin = MAX;for (j = 1;j<=n;j++)   if (!vis[j] && dis[j]<min)   {   min = dis[j];   u = j;   }vis[u]=1;sum += min;int k = pre[u];for (j = 1;j<=n;j++)   if (u!=j && vis[j])dp[u][j] = dp[j][u] = max(dp[j][k],min);for (j = 1;j<=n;j++)   if (!vis[j] && edge[u][j]<dis[j])   {  dis[j] = edge[u][j];  pre[j] = u;   }}}int main(){    int t = 0;    int i = 0,j = 0;    double ans;    scanf("%d",&t);    while(t--)    {       scanf("%d",&n);       for(i = 1;i<=n;i++)       {           scanf("%lf%lf%lf",&x[i],&y[i],&p[i]);           vis[i] = 0;           for(j = 1;j<i;j++)           {               edge[i][j] = edge[j][i] = d(x[i],x[j],y[i],y[j]);           }       }       prim();       ans = -MAX;       for(i = 1;i<=n;i++)          for(j = 1;j<i;j++)            ans = max(ans,(p[i]+p[j])/(sum-dp[i][j]));       printf("%.2lf\n",ans);    }    return 0;}


原创粉丝点击