• 【Uvalive 5834】 Genghis Khan the Conqueror (生成树,最优替代边)


    【题意】

      一个N个点的无向图,先生成一棵最小生成树,然后给你Q次询问,每次询问都是x,y,z的形式, 表示的意思是在原图中将x,y之间的边增大(一定是变大的)到z时,此时最小生成数的值是多少。最后求Q次询问最小生成树的平均值。 N<=3000 , Q<=10000

    Input
    There are no more than 20 test cases in the input.
    For each test case, the first line contains two integers N and M (1 ≤ N ≤ 3000, 0 ≤ M ≤ N × N),
    demonstrating the number of cities and roads in Pushtuar. Cities are numbered from 0 to N − 1. In
    the each of the following M lines, there are three integers xi
    , yi and ci (ci ≤ 107
    ), showing that there
    is a bidirectional road between xi and yi
    , while the cost of setting up guarders on this road is ci
    . We
    guarantee that the graph is connected. The total cost of the graph is less or equal to 109
    .
    The next line contains an integer Q (1 ≤ Q ≤ 10000) representing the number of suspicious road
    cost changes. In the following Q lines, each line contains three integers Xi
    , Yi and Ci showing that
    the cost of road (Xi
    , Yi) may change to Ci (Ci ≤ 107
    ). We guarantee that the road always exists and
    Ci
    is larger than the original cost (we guarantee that there is at most one road connecting two cities
    directly). Please note that the probability of each suspicious road cost change is the same.
    Output
    For each test case, output a real number demonstrating the expected minimal total cost. The result
    should be rounded to 4 digits after decimal point.
    Hint: The initial minimal cost is 5 by connecting city 0 to 1 and city 0 to 2. In the first suspicious
    case, the minimal total cost is increased to 6; the second case remains 5; the third case is increased to
    7. As the result, the expected cost is (5+6+7)/3 = 6.
    Sample Input
    3 3
    0 1 3
    0 2 2
    1 2 5
    3
    0 2 3
    1 2 6
    0 1 6
    0 0
    Sample Output
    6.0000

    【分析】

      WC这题做了我一整天!!!

      哭了!!!!

      死在所谓的树形DP上面了,啊啊啊啊啊,好垃圾啊。。

      我真的觉得这个TreeDP挺难搞的,虽然不难想,但是实现起来真的各种bug。。

      还是看了别人的题解才打出来TAT。。

      正题->_-> 

      这题的关键是在求出最小生成树之后求出去掉生成树任意一条边后剩下的两颗树的距离,可以证明这个距离就是最佳替换边的长度,而把原来最小生成树的边换成最佳替换边后所得到的生成树就是原图中去掉那条边的最小生成树,这个用反证法可以证明,如果新得到的树不是最小生成树可以推出原来的树也不是最小生成树。

      那么就是看一看是要用最小替换边,还是直接修改当前的边的值了。

      问题就是求最小替换边,用TreeDP实现。

      

      

      1. 用S1[i][j]表示树A中的点i 到 树B(j点所在的树)的最近距离,这个过程可以在一边dfs就可以出来,对于每个 i 的dfs 复杂度是O(n) ,外加一个n的循环求出每个点,这里的总复杂度为 O(n^2)。

      2. 通过求出来的S1[i][j] 再用一个dfs 求出  树B 到 树A的最近距离,(方法:枚举树A中的所有点 到 树B的最近距离,取其中的最小值。)显然, 这个求出来的值是我们要的最小替代边,把它保存到一个ANS[i][j]数组里面,(best[i][j]表示去掉边<i,j>后它的最小替代边的值)这里的总复杂度为 O(n^2)。

      打法好高级,主要是不能算上删掉的边,而其他的都要算上,这里挺难搞的。。

      

    看图吧,看图好懂一点。。

      1 #include<cstdio>
      2 #include<cstdlib>
      3 #include<cstring>
      4 #include<iostream>
      5 #include<algorithm>
      6 #include<queue>
      7 using namespace std;
      8 #define Maxn 3010
      9 #define INF 0xfffffff
     10 
     11 int dis[Maxn][Maxn];
     12 
     13 struct node
     14 {
     15     int x,y,c,next;
     16 }tt[Maxn*Maxn],t[2*Maxn];
     17 
     18 bool cmp(node x,node y) {return x.c<y.c;}
     19 
     20 int mymin(int x,int y) {return x<y?x:y;}
     21 int mymax(int x,int y) {return x>y?x:y;}
     22 int n,m;
     23 
     24 int fa[Maxn];
     25 int ffa(int x)
     26 {
     27     if(fa[x]!=x) fa[x]=ffa(fa[x]);
     28     return fa[x];
     29 }
     30 
     31 int first[Maxn],len;
     32 void ins(int x,int y,int c)
     33 {
     34     t[++len].x=x;t[len].y=y;t[len].c=c;
     35     t[len].next=first[x];first[x]=len;
     36 }
     37 
     38 int s1[Maxn][Maxn],ff[Maxn];
     39 int dfs(int x,int f,int rt)
     40 {
     41     s1[rt][x]=INF;
     42     for(int i=first[x];i;i=t[i].next) if(t[i].y!=f)
     43     {
     44         int y=t[i].y;
     45         s1[rt][x]=mymin(s1[rt][x],dfs(y,x,rt));
     46     }
     47     if(f!=rt) s1[rt][x]=mymin(s1[rt][x],dis[rt][x]);
     48     return s1[rt][x];
     49 }
     50 
     51 bool in[Maxn][Maxn];
     52 int ffind(int x,int f,int rt)
     53 {
     54     int now=s1[x][rt];
     55     for(int i=first[x];i;i=t[i].next) if(t[i].y!=f)
     56     {
     57         int y=t[i].y;
     58         now=mymin(now,ffind(y,x,rt));
     59     }
     60     return now;
     61 }
     62 
     63 int ans[Maxn][Maxn];
     64 int sum;
     65 void init()
     66 {
     67     memset(dis,63,sizeof(dis));
     68     for(int i=1;i<=m;i++)
     69     {
     70         int x,y,c;
     71         scanf("%d%d%d",&x,&y,&c);
     72         x++;y++;
     73         tt[i].x=x;tt[i].y=y;tt[i].c=c;
     74         dis[x][y]=dis[y][x]=c;
     75     }
     76     //kruskal
     77     sort(tt+1,tt+1+m,cmp);
     78     for(int i=1;i<=n;i++) fa[i]=i;
     79     int cnt=0;
     80     len=0;sum=0;
     81     memset(first,0,sizeof(first));
     82     // memset(ans,63,sizeof(ans));
     83     for(int i=1;i<=m;i++)
     84     {
     85         if(ffa(tt[i].x)!=ffa(tt[i].y))
     86         {
     87             fa[ffa(tt[i].x)]=ffa(tt[i].y);
     88             ins(tt[i].x,tt[i].y,tt[i].c);
     89             ins(tt[i].y,tt[i].x,tt[i].c);
     90             cnt++;
     91             sum+=tt[i].c;
     92         }
     93         if(cnt==n-1) break;
     94     }
     95 }
     96 
     97 void query()
     98 {
     99     int q;
    100     double fans=0;
    101     scanf("%d",&q);
    102     for(int i=1;i<=q;i++)
    103     {
    104         int x,y,c;
    105         scanf("%d%d%d",&x,&y,&c);
    106         x++;y++;
    107         if(in[x][y]) fans+=1.0*mymin(sum+c-dis[x][y],sum+ans[x][y]-dis[x][y]);
    108         else fans+=1.0*sum;
    109     }
    110     printf("%.4lf
    ",fans*1.0/q);
    111 }
    112 
    113 int main()
    114 {
    115     while(1)
    116     {
    117         scanf("%d%d",&n,&m);
    118         if(n==0&&m==0) break;
    119         init();
    120         for(int i=1;i<=n;i++) dfs(i,0,i);
    121         memset(ans,63,sizeof(ans));
    122         memset(in,0,sizeof(in));
    123         for(int i=1;i<=n;i++)
    124         {
    125             for(int j=first[i];j;j=t[j].next)
    126             {
    127                 int y=t[j].y;
    128                 ans[i][y]=ans[y][i]=mymin(ans[i][y],ffind(y,i,i));
    129                 in[i][y]=in[y][i]=1;
    130             }
    131         }
    132         query();
    133     }
    134     return 0; 
    135 }
    View Code

    2016-11-02 20:40:32

    哭了====再做一道k度限制生成树就不做了TAT。。

  • 相关阅读:
    IDEA 翻译插件网络错误
    win10 商店无法访问网络
    java 将中缀表达式转换成后缀表达式(逆波兰表达式)
    队列(Queue)
    单向链表
    Linux学习笔记2--------用户和组
    Linux学习笔记1-----------打包压缩,Vim
    如何修改主机名
    Linux的rpm软件包和yum软件包和wget
    Fiddler抓取电脑,手机https数据
  • 原文地址:https://www.cnblogs.com/Konjakmoyu/p/6024414.html
Copyright © 2020-2023  润新知