zoukankan      html  css  js  c++  java
  • F

    题目链接:https://vjudge.net/contest/67418#problem/F

    题目大意:给你一个图,让你加一条边,使得原图中的桥尽可能的小。(谢谢梁学长的帮忙)

    我对重边,tarjan算法中的各个数组的作用,以及需要哪些数组,还有一些不可取的地方。

    重边:原来一直以为无向图没有重边,,,在进行无向图的缩点的时候,假设 u- >已经走过了,那么 在不加重边的情况下,v- > u是不能走的。如果加重边了,u->v,这个时候,假设本来v-> u 是桥,但是加了之后就不是桥了。

    low数组: 这个数组存的是当前这个数能够到达最早的时间戳,注意low 数组不能用来判断染色。

    举个例子:(1,2) (2,1) (2,3) (3,4) (4,2) 这是五条边,如果按照正确的tarjan算法来跑到的话。

    1 1 1
    2 1 1
    3 2 1
    4 2 1(具体形式:编号 low数组的值 染色值),可以看到虽然这四个是一个联通块,但是每一个的low并不是都相等,这个地方就可以联想到tarjan的有向这个性质上了。

    dfn 数组:这个就是时间戳了。

    istack数组:这个数组的作用就是判断哪一些是联通块,哪一些点是在一个缩点里面的。

    我觉得tarjan 这三个数组就差不多够了,还有一个细节,在判断已经访问过的点的时候,这个时候需要更新,但是并不能访问已经缩好的点,否则的话,会将已经形成缩点的中的一部分点原来的值覆盖掉。

    树的直径

    我所理解的树的直径,就是树中最长的一条链。具体实现形式,首选任意选取这个图上的一个点,通过这个点进行bfs,找到最远的点,然后再通过最远的点进行bfs,再找到的长度就是这个树上的最长链了,也就是树的直径。

    我自己的证明方法:假设最长链是 u - v, 首先任意选取一个点,如果选取的这个点是最长链上的,那么第一次bfs找到的点一定是u或者v,然后再进行一次bfs的话,肯定能够将最长的链找出来。如果选取的点不是最长链上的,那么在寻找的过程中,肯定也能找到两个端点中的一个,也就是说肯定能找到最长链上的一个点,然后就和第一种情况相同了。

    对于这个题

    首先缩点是可以理解的,为了让形成的新的图尽可能的小(如果按照原图的话,寻找树的直径的我过程会超时),也就是联通的都形成一个缩点,然后剩下的边就肯定是桥了,这样的话,图就会变得比原来小多了。为什么这个题求最长直径就可以使得减少的桥的数目最多?首先,最长直径是对于缩点后的图来说的,如果把其中两个点连起来,这两个点原来形成的链上的边(也就是桥)都会消失,但是这两个点的相连并不会对其他的桥产生影响,因为该缩点的都缩起来了,所以这个题就需要找一个最长链,才能使得减少的桥数最多。

    AC代码:

      1 #include<iostream>
      2 #include<stack>
      3 #include<stdio.h>
      4 #include<map>
      5 #include<vector>
      6 #include<string>
      7 #include<cstring>
      8 #include<algorithm>
      9 #include<queue>
     10 #include<cmath>
     11 using namespace std;
     12 const int maxn = 200000+10;//注意宏定义!!!宏定义相乘会消耗比较多的时间
     13 # define ll long long
     14 # define inf 0x3f3f3f3f
     15 struct node
     16 {
     17     int nex;
     18     int to;
     19     int flag;
     20 } edge[maxn*10];
     21 struct point
     22 {
     23     int fr;
     24     int to;
     25 } po[maxn*10];
     26 int head[maxn],low[maxn],dfn[maxn],istack[maxn];
     27 int vis[maxn],dis[maxn];
     28 int n,m,k,num,maxx;
     29 int timeindex,col;
     30 stack<int>w;
     31 void init1()
     32 {
     33     memset(low,0,sizeof(low));
     34     memset(dfn,0,sizeof(dfn));
     35     memset(istack,0,sizeof(istack));
     36     while(!w.empty())w.pop();
     37     k=0;
     38     timeindex=0;
     39     col=0;
     40     maxx=0;
     41 }
     42 void init2()
     43 {
     44     memset(head,-1,sizeof(head));
     45     num=0;
     46 }
     47 void addedge(int fr,int to)
     48 {
     49     edge[num].to=to;
     50     edge[num].nex=head[fr];
     51     edge[num].flag=0;
     52     head[fr]=num++;
     53 }
     54 void tarjan(int u,int root)
     55 {
     56     low[u]=dfn[u]=++timeindex;
     57     w.push(u);
     58     for(int i=head[u]; i!=-1; i=edge[i].nex)
     59     {
     60         int v=edge[i].to;
     61         if(edge[i].flag)continue;
     62         edge[i].flag=edge[i^1].flag=1;
     63         if(dfn[v]==0)
     64         {
     65             tarjan(v,u);
     66             low[u]=min(low[u],low[v]);
     67             if(low[v]>dfn[u])
     68             {
     69                 po[++k].fr=u;
     70                 po[k].to=v;
     71             }
     72         }
     73         else if(istack[v]==0)//如果当前访问过的不是在已经形成的联通块里面在可以更新。
     74         {
     75             low[u]=min(low[u],dfn[v]);
     76         }
     77     }
     78     if(low[u]==dfn[u])
     79     {
     80         int t;
     81         col++;
     82         do
     83         {
     84             t=w.top();
     85             w.pop();
     86             istack[t]=col;
     87         }
     88         while(t!=u);
     89     }
     90 }
     91 int bfs(int t)
     92 {
     93     memset(vis,0,sizeof(vis));
     94     memset(dis,0,sizeof(dis));
     95     vis[t]=1;
     96     queue<int>q;
     97     q.push(t);
     98     int ind=0;
     99     while(!q.empty())
    100     {
    101         int top=q.front();
    102         q.pop();
    103         for(int i=head[top]; i!=-1; i=edge[i].nex)
    104         {
    105             int u=edge[i].to;
    106             if(vis[u])continue;
    107             vis[u]=1;
    108             dis[u]=dis[top]+1;
    109             if(dis[u]>maxx)
    110             {
    111                 maxx=dis[u];
    112                 ind=u;
    113             }
    114             q.push(u);
    115         }
    116     }
    117     return ind;
    118 }
    119 int main()
    120 {
    121     while(~scanf("%d %d",&n,&m)&&(n+m))
    122     {
    123         int t1,t2;
    124         init1();
    125         init2();
    126         for(int i=1; i<=m; i++)
    127         {
    128             scanf("%d %d",&t1,&t2);
    129             addedge(t1,t2);
    130             addedge(t2,t1);
    131         }
    132         tarjan(1,1);
    133         init2();
    134         for(int i=1; i<=k; i++)
    135         {
    136             addedge(istack[po[i].fr],istack[po[i].to]);//按照染色的数进行建图
    137             addedge(istack[po[i].to],istack[po[i].fr]);
    138         }
    139         int t=bfs(istack[po[1].fr]);
    140         bfs(t);
    141         // cout<<k<<" "<<maxx<<endl;
    142         printf("%d
    ",k-maxx);
    143     }
    144     return 0;
    145 }

     

  • 相关阅读:
    1293E. Xenon's Attack on the Gangs (树形DP)
    二分check的妙用
    Educational Codeforces Round 80 (CF
    CodeForces Goodbye2019 E.Divide Points (构造)
    POJ 1061 (拓展欧几里得+求最小正整数解)
    1238D
    关于Mysql用户的相关操作
    JAVA类的符号引用的理解
    关于tomcat的路径等基础问题
    Java 方法中,参数的装配顺序
  • 原文地址:https://www.cnblogs.com/letlifestop/p/10262804.html
Copyright © 2011-2022 走看看