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;
}

原文地址:https://www.cnblogs.com/csnd/p/12063272.html