hdu4756 最小树+树形dp

题意:
      给你一个完全图,让你在上面找到一颗最小树,然后问破坏这个最小树的某一条边后用其他边连接(要求最小)成新的树,然后输出破坏每一条边后最小树中最大的那个.

思路:
      先跑出一颗最小树,然后枚举树上的每一条边,当这条边被删除的时候,生成树就被分成了两个集合,然后找到一条最小的能让两个集合相通的替代边,最后输出最大的那个(树形dp优化),下面是我的ac记录


想法错了 求的次小树             WA
Kruskal + 并查集优化 暴力枚举   TLE
Kruskal + 树形DP                TLE
Prim    + 树形DP                AC


哎,这个题目时间卡的太紧了, 这个题目非得强调K是解决稀疏图的,P是解决稠密图的...

(下面的Prim之前没用过,之前用的是K,所以直接百度了个模板,然后写成结构体了,所以整个代码有点乱因为要配合百度来的Prim,自己懒啊,不想再看Prim了,只是记下他的模板了,以后遇到卡稠密图的题再粘过来.)


#include<stdio.h>
#include<string.h>
#include<math.h>

#define N (1000 + 100)

#define inf 100000000

typedef struct
{
   int x ,y;
}NODE;

typedef struct
{
   int a ,b;
   double dis;
}EDGE;

typedef struct
{
   int to ,next;
}STAR;

NODE node[N];
EDGE edge[N*N/2];
STAR E[N*2];

int list[N] ,tot; 
double map[N][N];
double dp[N][N];

bool camp(EDGE a ,EDGE b)
{
   return a.dis < b.dis;
}

void add(int a, int b)
{
   E[++tot].to = b;
   E[tot].next = list[a];
   list[a] = tot;
   
   E[++tot].to = a;
   E[tot].next = list[b];
   list[b] = tot;
}

double maxx(double a ,double b)
{
   return a > b ? a : b;
}

double minn(double a ,double b)
{
   return a < b ? a : b;
}

double q_dis(double x1 ,double y1 ,double x2 ,double y2)
{
   double x = x1 - x2;
   double y = y1 - y2;
   return sqrt(x * x + y * y);
}

double dfs(int p ,int s ,int f)
{
   double now = inf;
   for(int k = list[s] ;k ;k = E[k].next)
   {
      int to = E[k].to;
      if(to == f) continue;
      double tmp = dfs(p ,to ,s);
      now = minn(now ,tmp);
      dp[s][to] = dp[to][s] = minn(dp[s][to] ,tmp);
   }
   if(p != f) now = minn(now ,map[p][s]);
   return now;
}



struct PRIM //从0开始用 
{           
   double d[N];int vis[N];  
   bool mp[N][N];  //标记最小生成树上的边 
   double ans;//最小树 
   int n;//点的个数                           记得初始化    ***
   double dis[N][N]; // 距离                  记得初始化  *****
   
   
void prim()
{ 
    for(int i=0;i<n;i++)
    {  
        vis[i]=0;  
        d[i]=dis[0][i];  
    }  
    vis[0]=-1;  
    ans=0;  
    memset(mp,0,sizeof(mp));  
    for(int i=1;i<n;i++)
    {  
        double Min= inf;  
        int node=-1;  
        for(int j=0;j<n;j++)
        {  
            if(vis[j]!=-1 && d[j]<Min)
            {  
                node=j;  
                Min=d[j];  
            }  
        }  
  
        ans+=Min;  
        mp[vis[node]][node]=mp[node][vis[node]]=1;  
        add(vis[node],node); // 建树 
        vis[node]=-1;  
  
        for(int j=0;j<n;j++)
        {  
            if(vis[j]!=-1 && d[j]>dis[node][j])
            {  
                vis[j]=node;  
                d[j]=dis[node][j];  
            }  
        }  
    }  
 }
}P;

int main ()
{
   int t ,i ,j ,n;
   double pre;
   scanf("%d" ,&t);
   while(t --)
   {
      scanf("%d %lf" ,&n ,&pre);
      for(i = 0 ;i < n ;i ++)
      scanf("%d %d" ,&node[i].x ,&node[i].y);
      int tmp = 0;
      for(i = 0 ;i < n ;i ++)
      {
         for(j = i ;j < n ;j ++)
         {
            map[j][i] = map[i][j] = q_dis(node[i].x ,node[i].y ,node[j].x ,node[j].y);
            P.dis[i][j] = P.dis[j][i] = map[i][j];
            edge[++tmp].a = i;
            edge[tmp].b = j;
            edge[tmp].dis = map[i][j];
            dp[i][j] = dp[j][i] = inf;
         }
      }
      
      P.n = n;
      memset(list ,0 ,sizeof(list));
      tot = 1;
      P.prim();
      for(i = 1 ;i <= n ;i ++) dfs(i ,i ,-1);
      double T_sum = P.ans;
      double ans = T_sum;
      for(i = 1 ;i < n ;i ++)
      for(j = i + 1 ;j < n ;j ++)
      if(P.mp[i][j])
      ans = maxx(ans ,T_sum - map[i][j] + dp[i][j]);
      printf("%.2lf\n" ,ans * pre);
   }
   return 0;
}
         

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值