description:
給出乙個n個節點的有向圖,問題一:在其中至少選擇多少個節點才能使得從這些節點可以到達所有節點。 問題二:在其中至少要加多少條邊能才能使得其中的任一節點可以到達其他所有的節點。
input:
n 及n個節點的出邊
output:
兩個問題的答案
(bonus: 若要輸出方案怎麼做呢)
analysis:
和上一題一樣首先要將強連通分量縮點形成dag,然後就要用到dag上的一些性質。
這裡首先假設所得到的dag中,入度為0的點有a個,出度為0的點有b個。
問題一:答案為a
性質一:dag中所有入度不為0的點,一定可以從某個入度為0的點出發可達
證明:從任何入度非0的點逆著邊不斷往回走必然停止於某個入度為0的點,否則形成環與dag矛盾。
由性質一可知選擇所有的入度為0的點就足以使得這些點能夠到達圖中所有點,而顯然至少要選擇所有的入度為0的點,才有可能使得這些點可達全部點。所以問題一的答案就是dag圖中入度為0的點數,也就是a。
問題二:答案為max(a,b)
首選我們知道問題二的答案下限就是max(a,b),因為至少要給每乙個出度為0或者是入度為0的點至少連一條邊才有可能滿足條件,而如果這兩類點,兩兩相連也要min(a,b)個邊,還剩下max(a,b)-min(a,b)個點需要和其他點相連,這樣兩部分合起來就是max(a,b)
接下來要證明連max(a,b)個邊就足以滿足條件。這裡用到性質二。
性質二:和性質一類似,從dag上任何乙個點出發不斷往前走必然終止於乙個出度為0的點。(證明和性質一類似)
將性質一和性質二合起來可以知道,從任何乙個入度為0的起點出發不斷往下走,必然將走到乙個出度為0的點,而所有的這些路徑必然會覆蓋整個圖上的所有點,也就是說圖中每個點必然都至少在乙個這樣的路徑上,所以只要能把所有的出度為0和入度為0 的點連成乙個強連通分量就足以使得整個dag都強連通。那麼現在就比較自然了,下面分兩個部分將這兩類點連成強連通的。
首先必然能夠找到乙個將兩類點匹配的方式,匹配規則為從乙個入度為0點可以到達乙個出度為0點,將min(a,b)個入度為0的點和min(a,b)個出度為0的點兩兩匹配(孤立點被認為自己與自己匹配),然後還剩下max(a,b)-min(a,b)個多出來的入度為0或是出度為0的點。這樣就可以把原來的dag進行簡化,如下圖所示(假設a>b):
圖中藍色的點就是入度為0點,綠色的點就是出度為0點,有min(a,b)個匹配,以及一些額外max(a,b)-min(a,b)個藍點可達一些綠點,這裡只需要將匹配上的這兩類點首尾連線,就可以讓min(a,b)個匹配點及其所有中間路徑點都連在乙個環中,這一步需要新增min(a,b)條邊。如圖所示(紅邊為加入的邊):
至於孤立點(同時入度為0,出度為0)實際上還是一樣的只不過是中間路徑沒有點而已,同等的給它加乙個入邊加乙個出邊放入環中即可(圖中未畫出)
剩下的就只要把多出來的max(a,b)-min(a,b)那部分點(圖中為入度=0的點)直接和他的任意乙個終點加一條反向邊形成環即可,這一步中需要新增max(a,b)-min(a,b)條邊,如圖所示:
所以兩部分合起來就是max(a,b),可以看到此時整個圖是強連通的,每個點都可以到達任意的其他點。又由之前所看到的,這個問題的解的下限就是max(a,b),所以答案就是max(a,b)。
那麼如果要輸出問題二的方案的話,就是要先dfs一遍,找出哪些入度為0的點可以通往哪些出度為0的點,然後做個二分圖最大匹配,找到min(a,b)個匹配和max(a,b)-min(a,b)個額外點,然後輸出相應的邊即可。
當然,最後別忘了乙個特殊情況,若所有點已經是雙連通的,也就是dag只有乙個點的話,答案為0
#include#include#include#include#include#include#include#include#include#include#include#include#include#include#includeusing namespace std;
#define _for(i,a,b) for(int i=(a);i
#define _rep(i,a,b) for(int i=(a);i<=(b);++i)
typedef long long ll;
const int inf = 1 << 30;
const int mod = 1000000007;
const int maxn = 105;
int n;
vector> g(maxn);
int dfn[maxn], low[maxn], time, idx, color[maxn];
int ind[maxn], oud[maxn];
stacksta;
void tarjan(int u)
else if (!color[v])
} if (low[u] == dfn[u]) }}
int main()
} time = idx = 0;
memset(dfn, 0, sizeof(dfn));
memset(color, 0, sizeof(color));
for (int i = 1; i <= n; ++i)if (!dfn[i])
memset(ind, 0, sizeof(ind));
memset(oud, 0, sizeof(oud));
for(int i=1;i<=n;++i)
for (int j = 0; j < g[i].size(); ++j)
}int ans1, ans2;
if (idx == 1)
else
ans1 = cnt1; ans2 = max(cnt1, cnt2);
printf("%d\n%d\n", ans1, ans2);
} }
return 0;
}
POJ 1236 強連通分量
題目鏈結 翻譯一下題目吧,大致含義就是,有n個學校,現在要向n個學校傳遞乙個軟體,如果a學校願意支援b學校,那麼給了a,a就會給b,但是a支援b但是b不一定支援a 有向圖警告 要求什麼呢,最少給多少個學校就可以給到全部的學校,最少加幾個支援關係,可以使得給任意乙個學校就可以傳遞到全部學校去。思路 第...
poj 1236 強連通分量
題目大意 給定乙個n n 100 個點的有向圖,問 q1 最少需要選擇多少個點,使得從這些點出發能遍歷完整個圖 q2 最少需要新增多少條有向邊,使得整個圖成為強連通圖 分析 求出強連通分量後進行縮點,得到每個強連通分量的入度in,出度out q1 入度為0的強連通分量個數 q2 max 入度為0的強...
poj1236 強連通分量 縮點
題意 n 2 題解 找強連通分量,縮點。記f i 為縮完點後的新圖中各點入度,g i 為出度,ans1為f i 0的點的數目,ans2為g i 0的點的數目則第一問為ans1,第二問則為max。至於第二問的解釋,我的想法是對於得到的dag圖,考慮其中的出度為0的點和入度為0的點組成的點集v,將這些點...