zoukankan      html  css  js  c++  java
  • hdu4126(MST + 树形dp

    题意:
          这个题目和hdu4756差不多,是给你一个图,然后是q次改变边的权值,权值只增不减,最后问你每次改变之后的最小树的平均值是多少.


    思路:(prim+树形dp)

          先跑一边最小树(建议用普利姆,别用克鲁斯卡尔,虽然网上有用k过的,但我感觉理论上会超时 n*n*nlog(n)/2),然后树形dp跑出任意两个集合之间的最有替代边.(n^2),然后当每次输入一条要该边的边的时候,先判断先是不是最小树上的边,如果不是那么sum直接加最小树,如果是那么就用sum - dis[u][v] + min(dis ,dp[u][v]);就是用原边和不用原边的最小值,记住此时的原边权值已经改变....


    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    
    #define N (3000 + 100)
    #define inf 9223372036854775807
    
    using namespace std;
    
    typedef struct
    {
       int to ,next;
    }STAR;
    
    STAR E[N*2];
    int list[N] ,tot;
    double map[N][N];
    double dp[N][N];
    
    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 minn(double a ,double b)
    {
       return a < b ? a : b;
    }
    
    double DFS_T_DP(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_T_DP(p ,to ,s);
          now = minn(tmp ,now);
          dp[s][to] = dp[to][s] = minn(dp[s][to] ,tmp);
       }  
       if(f != p)
       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 n ,m ,q ,i ,j ,a ,b;
       double dis;
       while(~scanf("%d %d" ,&n ,&m) && n + m)
       {
          for(i = 0 ;i <= n ;i ++)
          {
             for(j = i + 1 ;j <= n ;j ++)
             P.dis[i][j] = P.dis[j][i] = map[i][j] = map[j][i] = dp[i][j] = dp[j][i] = inf;
             P.dis[i][i] = P.dis[i][i] = map[i][i] = map[i][i] = 0;
          }
          for(i = 1 ;i <= m ;i ++)
          {
             scanf("%d %d %lf" ,&a ,&b ,&dis);
             map[a][b] = map[b][a] = dis;
             P.dis[a][b] = P.dis[b][a] = dis;
          }
          P.n = n;
          memset(list ,0 ,sizeof(list));
          tot = 1;
          P.prim();
          double T_sum = P.ans;
          for(i = 0 ;i < n ;i ++)
          DFS_T_DP(i ,i ,-1);
          double ans_sum = 0;   
          scanf("%d" ,&q);    
          for(i = 1 ;i <= q ;i ++)
          {
             scanf("%d %d %lf" ,&a ,&b ,&dis);
             double now;
             if(!P.mp[a][b])
             now = T_sum ;
             else
             {
                if(dis > dp[a][b])
                now = T_sum - map[a][b] + dp[a][b] ;
                else
                now = T_sum - map[a][b] + dis ;
             }
             ans_sum += now;
          }
          printf("%.4lf
    " ,ans_sum / q);
       }
       return 0;
    }
    

  • 相关阅读:
    (Vue中)cehart在同一个dom上画图图切换时饼图有折线图的坐标系
    linux(centos7)修改服务器时间
    centos6 yum源不能使用
    Linux 使用 history 来减少重复命令的几个实用技巧。
    7个Shell 拿来就用脚本实例!
    keepalived的配置解析&安装与爬坑
    linux最全命令使用手册
    linux各种误删文件恢复方法(经典强推)
    位运算符
    SQL 书写、执行顺序
  • 原文地址:https://www.cnblogs.com/csnd/p/12063271.html
Copyright © 2011-2022 走看看