您的位置:首页 > 其它

POJ-1236(有向图强连通分量 + 缩点 + 加边使得整个图强连通)

2014-08-14 15:48 501 查看
题目:http://poj.org/problem?id=1236

感觉是强连通问题的一道典型题目,还是有很多地方没有注意到,看了discuss才发现:

(1)当整个图已经是一个SCC时

(2)对于SCC缩点后的DAG,实际上等于问我们需要加多少条有向边,使得整个DAG变为强连通,因此,我们要给每个入度为0的点(设有A个)加一条入边,给每个出度为0的点(设有B个)加一条出边,而这些加上的边有重合,那到底要加几条呢,实际上是max(A, B)个



#include <cstdio>
#include <cstring>
#include <vector>
#include <stack>
#include <algorithm>
using namespace std;
#define MAX     101

int N, dfsClock, pre[MAX];
int sccCnt, sccno[MAX], sccOutDegree[MAX], sccInDegree[MAX];
vector<int> list[MAX], scc[MAX];
stack<int> st;

int dfs(int x)
{
int lowx, y, lowy;
const vector<int>& v = list[x];

lowx = pre[x] = ++dfsClock;
st.push(x);
for(int i = 0, n = v.size(); i < n; ++i){
y = v[i];
if(!pre[y]){
lowy = dfs(y);
lowx = min(lowx, lowy);
}
else if(!sccno[y]) lowx = min(lowx, pre[y]);
}
if(lowx == pre[x]){
++sccCnt;
scc[sccCnt].clear();
while(true){
y = st.top(); st.pop();
sccno[y] = sccCnt;
scc[sccCnt].push_back(y);
if(y == x) break;
}
}
return lowx;
}
void findScc()
{
memset(pre + 1, 0, N << 2);
memset(sccno + 1, 0, N << 2);
dfsClock = sccCnt = 0;
for(int i = 1; i <= N; ++i){
if(!pre[i]) dfs(i);
}
}
void findSccInOutDegree()
{
bool out[MAX];
memset(sccInDegree + 1, 0, sccCnt << 2);
for(int i = 1; i <= sccCnt; ++i){
memset(out + 1, false, sccCnt);
int degree = 0;
const vector<int>& v = scc[i];
for(int j = 0, n = v.size(); j < n; ++j){
const vector<int>& l = list[v[j]];
for(int k = 0, m = l.size(); k < m; ++k){
int no = sccno[l[k]];
if(no != i && !out[no]){
out[no] = true;
++degree;
++sccInDegree[no];
}
}
}
sccOutDegree[i] = degree;
}
}
void solve()
{
findScc();
findSccInOutDegree();
if(sccCnt == 1){
puts("1\n0");
return;
}

int noInScc = 0, noOutScc = 0;
for(int i = 1; i <= sccCnt; ++i){
if(!sccInDegree[i]) ++noInScc;
if(!sccOutDegree[i]) ++noOutScc;
}
printf("%d\n%d\n", noInScc, max(noInScc, noOutScc));
}
bool input()
{
if(1 != scanf("%d", &N)) return false;
int j;
for(int i = 1; i <= N; ++i){
list[i].clear();
while(scanf("%d", &j), j){
list[i].push_back(j);
}
}
return true;
}

int main()
{
while(input()) solve();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: