hdu 4612 Warm up(无向图Tarjan+树的直径)

 

hdu 4612 Warm up(无向图Tarjan+树的直径)

分类: 图论   274人阅读  评论(0)  收藏  举报
题意:有N个点,M条边(有重边)的无向图,这样图中会可能有桥,问加一条边后,使桥最少,求该桥树。

思路:这个标准想法很好想到,缩点后,求出图中的桥的个数,然后重建图必为树,求出树的最长直径,在该直径的两端点连一边,则图中的桥会最少。
从这题中学到两点,所以写一下解题报告。
1.官方说judge的栈小,得手动增栈 #pragma comment(linker,"/STACK:102400000,102400000") 以前没见过,算是学习了。
2.对改正了对Tarjan算法的一个错误理解,以前看某人博客说,无向图中,Tarjan后low值相等的点属于同一块,以前这样判断过,也过了挺多题。但跟别人讨论后发现是错的。。。。。

3.以前没用Tarjan写过无向图,不懂正向边访问过,标志反向边,这次学习了。


[cpp]  view plain copy
  1. //937MS    41304K  
  2. #pragma comment(linker, "/STACK:102400000,102400000")  
  3. #include  
  4. #include  
  5. const int VM = 200005;  
  6. const int EM = 1000005;  
  7.   
  8. struct Edeg  
  9. {  
  10.     int to,nxt,vis;  
  11. }edge[EM<<1],tree[EM<<1];  
  12.   
  13. int head[VM],vis[VM],thead[VM];  
  14. int dfn[VM],low[VM],stack[VM],belong[VM];  
  15. int ep,bridge,son,maxn,src,n,cnt,scc,top;  
  16.   
  17. int max (int a,int b)  
  18. {  
  19.     return a > b ? a : b;  
  20. }  
  21. int min(int a ,int b)  
  22. {  
  23.     return a > b ? b : a;  
  24. }  
  25. void addedge (int cu,int cv)  
  26. {  
  27.     edge[ep].to = cv;  
  28.     edge[ep].vis = 0;  
  29.     edge[ep].nxt = head[cu];  
  30.     head[cu] = ep ++;  
  31.     edge[ep].to = cu;  
  32.     edge[ep].vis = 0;  
  33.     edge[ep].nxt = head[cv];  
  34.     head[cv] = ep ++;  
  35. }  
  36. void Buildtree(int cu,int cv)  
  37. {  
  38.     tree[son].to = cv;  
  39.     tree[son].nxt = thead[cu];  
  40.     thead[cu] = son ++;  
  41. }  
  42. void Tarjan (int u)  
  43. {  
  44.     int v;  
  45.     vis[u] = 1;  
  46.     dfn[u] = low[u] = ++cnt;  
  47.     stack[top++] = u;  
  48.     for (int i = head[u];i != -1;i = edge[i].nxt)  
  49.     {  
  50.         v = edge[i].to;  
  51.         if (edge[i].vis) continue//  
  52.         edge[i].vis = edge[i^1].vis = 1; //正向边访问过了,反向边得标志,否则两点会成一块。  
  53.         if (vis[v] == 1)  
  54.             low[u] = min(low[u],dfn[v]);  
  55.         if (!vis[v])  
  56.         {  
  57.             Tarjan (v);  
  58.             low[u] = min(low[u],low[v]);  
  59.             if (low[v] > dfn[u])  
  60.                 bridge ++;  
  61.         }  
  62.     }  
  63.     if (dfn[u] == low[u])  
  64.     {  
  65.         ++scc;  
  66.         do{  
  67.             v = stack[--top];  
  68.             vis[v] = 0;  
  69.             belong[v] = scc;  
  70.         }while (u != v);  
  71.     }  
  72. }  
  73. void BFS(int u)  
  74. {  
  75.     int que[VM+100];  
  76.     int front ,rear,i,v;  
  77.     front = rear = 0;  
  78.     memset (vis,0,sizeof(vis));  
  79.     que[rear++] = u;  
  80.     vis[u] = 1;  
  81.     while (front != rear)  
  82.     {  
  83.         u = que[front ++];  
  84.         front = front % (n+1);  
  85.         for (i = thead[u];i != -1;i = tree[i].nxt)  
  86.         {  
  87.             v = tree[i].to;  
  88.             if (vis[v]) continue;  
  89.             vis[v] = 1;  
  90.             que[rear++] = v;  
  91.             rear = rear%(n+1);  
  92.         }  
  93.     }  
  94.     src = que[--rear];//求出其中一个端点  
  95. }  
  96. void DFS (int u,int dep)  
  97. {  
  98.     maxn = max (maxn,dep);  
  99.     vis[u] = 1;  
  100.     for (int i = thead[u]; i != -1; i = tree[i].nxt)  
  101.     {  
  102.         int v = tree[i].to;  
  103.         if (!vis[v])  
  104.             DFS (v,dep+1);  
  105.     }  
  106. }  
  107. void solve()  
  108. {  
  109.     int u,v;  
  110.     memset (vis,0,sizeof(vis));  
  111.     cnt = bridge = scc = top = 0;  
  112.     Tarjan (1);  
  113.     memset (thead,-1,sizeof(thead));  
  114.     son = 0;  
  115.     for (u = 1;u <= n;u ++)              //重构图  
  116.         for (int i = head[u];i != -1;i = edge[i].nxt)  
  117.         {  
  118.             v = edge[i].to;  
  119.             if (belong[u]!=belong[v])  
  120.             {  
  121.                 Buildtree (belong[u],belong[v]);  
  122.                 Buildtree (belong[v],belong[u]);  
  123.             }  
  124.         }  
  125.     maxn = 0;    //最长直径  
  126.     BFS(1);      //求树直径的一个端点  
  127.     memset (vis,0,sizeof(vis));  
  128.     DFS(src,0); //求树的最长直径  
  129.     printf ("%d\n",bridge-maxn);  
  130. }  
  131.   
  132. int main ()  
  133. {  
  134.     #ifdef LOCAL  
  135.         freopen ("in.txt","r",stdin);  
  136.     #endif  
  137.     int m,u,v;  
  138.     while (~scanf ("%d%d",&n,&m))  
  139.     {  
  140.         if (n == 0&&m == 0)  
  141.             break;  
  142.         memset (head,-1,sizeof(head));  
  143.         ep = 0;  
  144.         while (m --)  
  145.         {  
  146.             scanf ("%d%d",&u,&v);  
  147.             addedge (u,v);  
  148.         }  
  149.         solve();  
  150.     }  
  151.     return 0;  
  152. }  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值