zoukankan      html  css  js  c++  java
  • 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
    " ,ans * pre);
       }
       return 0;
    }
             
    

  • 相关阅读:
    关于相对定位与绝对定位
    一些常用但不平凡的CSS属性
    Java-认识变量、注释并能及时发现错误
    了解Java并学会创建Java项目(一个菜鸟的成长历程)
    竞态条件
    web服务器原理
    信号
    静态网页与动态网页区别
    mmap
    HTTP协议
  • 原文地址:https://www.cnblogs.com/csnd/p/12063277.html
Copyright © 2011-2022 走看看