您的位置:首页 > 其它

USACO Network of Schools 解题报告

2014-10-10 02:08 295 查看
这道题是看了大神的解释才明白原来是求强连通分量(SCC, strongly connected components):https://www.byvoid.com/blog/usaco-533-schlnet。

GeeksforGeeks上面有求SCC的两种方法,讲得很详细:
http://www.geeksforgeeks.org/strongly-connected-components/ http://www.geeksforgeeks.org/tarjan-algorithm-find-strongly-connected-components/
包括跑两遍DFS中间加一个reverse的比较好理解的,也包括Tarjan的一遍DFS的。这里用的是后者。大神那里是前者。跑一遍DFS做法从时间上看比大神的跑两遍DFS的方法还慢,我估计主要原因是大神用的是array,我这里用的是vector。不过也不是很确定是不是这个原因。但是两遍DFS确实要好想些。

Executing...
Test 1: TEST OK [0.003 secs, 3508 KB]
Test 2: TEST OK [0.005 secs, 3508 KB]
Test 3: TEST OK [0.003 secs, 3508 KB]
Test 4: TEST OK [0.005 secs, 3508 KB]
Test 5: TEST OK [0.008 secs, 3508 KB]
Test 6: TEST OK [0.011 secs, 3508 KB]
Test 7: TEST OK [0.008 secs, 3508 KB]
Test 8: TEST OK [0.005 secs, 3508 KB]
Test 9: TEST OK [0.014 secs, 3508 KB]
Test 10: TEST OK [0.005 secs, 3508 KB]
Test 11: TEST OK [0.008 secs, 3508 KB]

All tests OK.


/*
ID: thestor1
LANG: C++
TASK: schlnet
*/
#include <iostream>
#include <fstream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <climits>
#include <cassert>
#include <string>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <algorithm>
#include <cassert>

using namespace std;

// A recursive function that finds and prints strongly connected
// components using DFS traversal
// u --> The vertex to be visited next
void SCC(int u, vector<vector<int> > &sccs, vector<int> &dist, vector<int> &low, stack<int> &st, vector<int> &inStack, int ×tamp, const vector<vector<int> > &adjs)
{
// Initialize discovery time and low value
dist[u] = low[u] = timestamp;
timestamp++;
st.push(u);
inStack[u] = true;

for (int i = 0; i < adjs[u].size(); ++i)
{
int v = adjs[u][i];
// If v is not visited yet, then recur for it
if (dist[v] < 0)
{
SCC(v, sccs, dist, low, st, inStack, timestamp, adjs);
low[u] = min(low[u], low[v]);
}
else if (inStack[v])
{
//// Update low value of 'u' only of 'v' is still in stack
// (i.e. it's a back edge, not cross edge).
low[u] = min(low[u], low[v]);
}
}

// head node found, pop the stack and generate an SCC
if (dist[u] == low[u])
{
int v;
std::vector<int> scc;
while (st.top() != u)
{
v = st.top();
// assert(low[v] == low[u]);
scc.push_back(v);
st.pop();
inStack[v] = false;
}
v = st.top();
assert(v == u);
scc.push_back(v);
st.pop();
inStack[v] = false;

sccs.push_back(scc);
}
}

int main()
{
ifstream fin("schlnet.in");
ofstream fout("schlnet.out");

int N;
fin>>N;
vector<vector<int> > adjs(N, vector<int>());
for (int i = 0; i < N; ++i)
{
int v;
fin>>v;
while (v != 0)
{
adjs[i].push_back(v - 1);
fin>>v;
}
}
fin.close();

// for (int i = 0; i < N; ++i)
// {
// 	cout<<i<<":";
// 	for (int j = 0; j < adjs[i].size(); ++j)
// 	{
// 		cout<<adjs[i][j]<<"\t";
// 	}
// 	cout<<endl;
// }

vector<vector<int> > sccs;
vector<int> dist(N, -1);
vector<int> low(N, -1);
stack<int> st;
vector<int> inStack(N, false);
int timestamp = 0;
for (int u = 0; u < N; ++u)
{
if (dist[u] < 0)
{
SCC(u, sccs, dist, low, st, inStack, timestamp, adjs);
}
}

// cout<<"sccs:"<<endl;
// for (int i = 0; i < sccs.size(); ++i)
// {
// 	for (int j = 0; j < sccs[i].size(); ++j)
// 	{
// 		cout<<sccs[i][j]<<", low: "<<low[sccs[i][j]]<<", dist: "<<dist[sccs[i][j]]<<endl;
// 	}
// }
if (sccs.size() == 1)
{
fout<<1<<endl;
fout<<0<<endl;
}
else
{
std::vector<int> sccid(N, 0);
for (int i = 0; i < sccs.size(); ++i)
{
for (int j = 0; j < sccs[i].size(); ++j)
{
sccid[sccs[i][j]] = i;
}
}

// cout << "sccid:" << endl;
// for (int i = 0; i < sccid.size(); ++i)
// {
// 	cout << i << "," << sccid[i]<<endl;
// }

// std::vector<std::vector<int> > dense(sccs.size(), std::vector<int>());

std::vector<int> in(sccs.size(), 0);
std::vector<int> out(sccs.size(), 0);
for (int u = 0; u < adjs.size(); ++u)
{
for (int i = 0; i < adjs[u].size(); ++i)
{
// sccid[u], sccid[adjs[u][i]]
// dense[sccid[u]].push_back(sccid[adjs[u][i]]);
// dense[sccid[adjs[u][i]]].push_back(sccid[u]);
if (sccid[u] != sccid[adjs[u][i]])
{
in[sccid[adjs[u][i]]]++;
out[sccid[u]]++;
}
}
}

int incnt = 0, outcnt = 0;
for (int i = 0; i < sccs.size(); ++i)
{
if (in[i] == 0)
{
incnt++;
}
if (out[i] == 0)
{
outcnt++;
}
}

fout<<incnt<<endl;
fout<<max(incnt, outcnt)<<endl;
}

fout.close();
return 0;
}


assert(low[v] == low[u]);
这句有时是无法成立的。不知道为啥。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: