日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

POJ 2186 popular cow 有向图的强联通问题 Tarjan算法

發布時間:2025/6/15 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 POJ 2186 popular cow 有向图的强联通问题 Tarjan算法 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

參考:http://hi.baidu.com/1093782566/blog/item/e5a0e9229913bd048b82a175.html

http://www.cppblog.com/IronOxide/archive/2010/08/16/123622.html?opt=admin


題目簡述:n頭奶牛,給出若干個歡迎關系a b,表示a歡迎b,歡迎關系是單向的,但是是可以傳遞的。另外每個奶牛都是歡迎他自己的。求出被所有的奶牛歡迎的奶牛的數目。
模型轉換:N個頂點的有向圖,有M條邊(N≤10000,M≤50000)。求一共有多少個點,滿足這樣的條件:所有其它的點都可以到達這個點。
首先,這個題的N和M都非常大,硬做是肯定不行的。考慮如果這個圖是一棵樹,那么問題就變的很簡單了,因為至多有一個點滿足條件,這個點滿足條件的充要條件是:這個點是樹中唯一的出度為0的點。

那么我們能否把圖轉化為樹呢?首先可以想到的是,如果圖中包含有環,那么就可以把這個環縮成一個點,因為環中的任意兩個點可以到達,環中所有的點具有相同的性質,即它們分別能到達的點集都是相同的,能夠到達它們的點集也是相同的。縮點后的圖必無環,否則,可將環上所有點也縮成一個點,與極大強聯通分量矛盾。


那么是否只有環中的點才具有相同的性質呢?進一步的考慮,圖中的每一個極大強連通分支中的點都具有相同的性質。所以,如果把圖中的所有極大強連通分支求出后,就可以把圖收縮成一棵樹,問題就迎刃而解了。

預備知識:有向圖的強連通分量的求法,這個和求割點的算法差不多。
算法框架:對有向圖求強連通分量,然后找出所有獨立的強連通分量(所謂獨立,就是該連通分量里面的點到外面的點沒有通路,當然,連通分量外的點是可以有路到強連通分量內的點的),如果獨立的強連通分量的數目只有一個,那么,就輸出這個強連通分量內解的個數,否則輸出無解。只要找到縮點后的圖中無出度的點的個數,設為cnt, 若 cnt > 1 , 則必無滿足條件的點,因為一個出度為

零的點無法到達另一個出度為零的點;若cnt = 1 , 則該點所對應的強聯通分量的點的個數即為答案。


算法證明:
1:假設a和b都是最受歡迎的cow,那么,a歡迎b,而且b歡迎a,于是,a和b是屬于同一個連通分量內的點,所有,問題的解集構成一個強連通分量。
2:如果某個強連通分量內的點a到強連通分量外的點b有通路,因為b和a不是同一個強連通分量內的點,所以b到a一定沒有通路,那么a不被b歡迎,于是a所在的連通分量一定不是解集的那個連通分量。
3:如果存在兩個獨立的強連通分量a和b,那么a內的點和b內的點一定不能互相到達,那么,無論是a還是b都不是解集的那個連通分量,問題保證無解。

4:如果圖非連通,那么,至少存在兩個獨立的連通分量,問題一定無解。

[cpp]?view plaincopy
  • #include?<iostream>??
  • #include?<stack>??
  • #include?<cstring>??
  • using?namespace?std;??
  • ??
  • const?int?MAXN?=?10000?+?10;?????//?點的最大數量??
  • const?int?MAXM?=?50000?+?10;?????//?邊的最大數量??
  • ??
  • //?假設對邊u-->v??
  • struct?EDGE??
  • {??
  • ?int?v;????????????????????//?從u點出發能到達的點v??
  • ?int?next;?????????????????//?從u點出發能到達的下一條邊的編號??
  • };??
  • ??
  • stack<int>?s;??
  • EDGE?edge[MAXM];??
  • int?low[MAXN];?????????????//?low[u]:是u或u的子樹能夠追溯到的最早的棧中節點的次序號??
  • int?dfn[MAXN];?????????????//?dfn[u]:節點u搜索的次序編號(時間戳)??
  • int?first[MAXN];?????????????//?first[u]?=?e:從點u出發的最后一條邊的編號是e(“最后”是指最后輸入)??
  • int?sccf[MAXN];????????????//?sccf[i]?=?j:第i個點所在的強連通分量的編號??
  • bool?ins[MAXN];????????????//?是否在棧中??
  • int?outdegree[MAXN];???????//?強連通分量的出度??
  • int?index;?????????????????//?次序編號??
  • int?scc;???????????????????//?強連通分量的數目??
  • int?n,?m;??
  • ??
  • ??
  • void?Init()??
  • {??
  • ????scc?=?0;??
  • ????index?=?1;??
  • ????memset(low,?0,?sizeof(low));??
  • ????memset(dfn,?0,?sizeof(dfn));??
  • ????memset(ins,?false,?sizeof(ins));??
  • ????memset(sccf,?0,?sizeof(sccf));??
  • ????memset(first,?-1,?sizeof(first));??
  • }??
  • ??
  • void?Tarjan(int?u)??
  • {??
  • ????int?v;??
  • ????low[u]?=?dfn[u]?=?index++;??
  • ????s.push(u);??
  • ????ins[u]?=?true;??
  • ????//?枚舉每一條邊:u-->v??
  • ????for?(int?k=first[u];?k!=-1;?k=edge[k].next)??
  • ????{??
  • ????????v?=?edge[k].v;??
  • ????????if?(dfn[v]?==?0)??
  • ????????{??
  • ????????????Tarjan(v);??
  • ????????????low[u]=min(low[u],low[v]);??
  • ????????}??
  • ????????else?if?(ins[v])??
  • ????????{??
  • ????????????low[u]=min(low[u],dfn[v]);??
  • ????????}??
  • ????}??
  • ????//?如果節點u是強連通分量的根??
  • ????if?(dfn[u]?==?low[u])??
  • ????{??
  • ????????scc++;??
  • ????????do??
  • ????????{??
  • ????????????v?=?s.top();??
  • ????????????s.pop();??
  • ????????????ins[v]?=?false;??
  • ????????????sccf[v]?=?scc;??
  • ????????}while?(u?!=?v);??
  • ????}??
  • }??
  • ??
  • ??
  • ??
  • ??
  • ??
  • //?獲得超級受喜歡的cows的數量??
  • ??
  • int?GetSuperPopularNum()??
  • {??
  • ????int?u,?v;??
  • ????int?cnt?=?0;????//?出度為0的強連通分量的數目??
  • ????int?ct[MAXN];????//?ct[i]?=?j:強連通分量i有j個點??
  • ??
  • ????memset(outdegree,?0,?sizeof(outdegree));??
  • ????memset(ct,?0,?sizeof(ct));??
  • ??
  • ??
  • ??
  • ????//?枚舉每一個點u:求outdegree和ct??
  • ????for?(u=1;?u<=n;?u++)??
  • ????{??
  • ????????ct[sccf[u]]++;??
  • ????????for?(int?k=first[u];?k!=-1;?k=edge[k].next)??
  • ????????{??
  • ????????????//?對每條邊u-->v??
  • ????????????v?=?edge[k].v;??
  • ????????????if?(sccf[u]?!=?sccf[v])??
  • ????????????{??
  • ????????????????outdegree[sccf[u]]++;??
  • ????????????}??
  • ????????}??
  • ????}??
  • ??
  • ????//?數數強連通分量為0的點有多少個??
  • ????for?(u=1;?u<=scc;?u++)??
  • ????{??
  • ????????if?(outdegree[u]?==?0)??
  • ????????{??
  • ????????????cnt++;??
  • ????????????v?=?u;??
  • ????????}??
  • ????}??
  • ??
  • ????return?(cnt?==?1)??ct[v]?:?0;??
  • }??
  • ??
  • ??
  • ??
  • int?main()??
  • {??
  • ????int?i,?u,?v;??
  • ????int?e?=?0;??????//?邊的數量,建圖時會用到??
  • ??
  • ????//?初始化數據并建圖??
  • ????Init();??
  • ????cin?>>?n?>>?m;??
  • ????for?(i=0;?i<m;?i++)??
  • ????{??
  • ????????cin?>>?u?>>?v;??
  • ????????edge[e].v?=?v;??
  • ????????edge[e].next?=?first[u];??
  • ????????first[u]?=?e;??
  • ????????e++;??
  • ????}??
  • ??
  • ????//?求強連通分量??
  • ????for?(i=1;?i<=n;?i++)??
  • ????{??
  • ????????if?(dfn[i]?==?0)??
  • ????????{??
  • ????????????Tarjan(i);??
  • ????????}??
  • ????}??
  • ??
  • ????//?輸出答案??
  • ????cout?<<?GetSuperPopularNum()?<<?endl;??
  • ??
  • ????return?0;??
  • }??
  • 《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀

    總結

    以上是生活随笔為你收集整理的POJ 2186 popular cow 有向图的强联通问题 Tarjan算法的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。