USACO Network of Schools 解题报告

这道题是看了大神的解释才明白原来是求强连通分量(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]);
这句有时是无法成立的。不知道为啥。




你可能感兴趣的:(USACO Network of Schools 解题报告)