Cod sursa(job #23187)

Utilizator bogdan2412Bogdan-Cristian Tataroiu bogdan2412 Data 28 februarie 2007 14:00:10
Problema Santa Scor 0
Compilator cpp Status done
Runda Arhiva de probleme Marime 5.12 kb
#include <cstdio>
#include <vector>
#include <queue>
#include <algorithm>

using namespace std;

#define MAXN 45005

int N, M;
int S, D, Qs;
vector<int> con[MAXN];
int alt[MAXN], p[MAXN], low[MAXN], art[MAXN], u[MAXN];

vector<int> nodincomp[MAXN];
vector< vector<int> > compnod;
vector< vector< pair<int, int> > > compmuc;
vector<bool> usecomp, usenod;

vector< pair<int, int> > st;

/*
 * introduce muchia (a, b) in stiva
 */
void push(int a, int b) { st.push_back( make_pair(a, b) ); }

/*
 * extrage componenta biconexa
 * scoate muchii din stiva pana ajunge la (a, b)
 */
void popcomp(int a, int b)
{
	vector<int> noduri;
	vector< pair<int, int> > muchii;

	noduri.clear(); muchii.clear();

	for (; 1; st.pop_back())
	{
		noduri.push_back( st.back().first );
		noduri.push_back( st.back().second );
		muchii.push_back( st.back() );

		if ( st.back() == make_pair(a, b) )
		{
			st.pop_back();
			break;
		}
	}

	sort(noduri.begin(), noduri.end());
	sort(muchii.begin(), muchii.end());

	noduri.resize( unique(noduri.begin(), noduri.end()) - noduri.begin() );
	muchii.resize( unique(muchii.begin(), muchii.end()) - muchii.begin() );

	compnod.push_back( noduri );
	compmuc.push_back( muchii );
	usecomp.push_back( false );			//aflu mai tarziu daca componenta respectiva e pe drumu piticilor :)
							//drumul piticilor va fi un sir de componente biconexe si puncte de articulatie
							//fiecare punct de articulatie va aparea doar o data in drum si astfel se va trece
							//prin maxim 2 componente biconexe legate de orice punct de articulatie
	for (size_t i = 0; i < noduri.size(); i++)
		nodincomp[ noduri[i] ].push_back( (int)compnod.size() - 1 );
}

/*
 * afla componentele biconexe
 */
void dfs(int k)
{
	int NCHILD = 0;					//numarul de fii in arborele DF al nodului curent, util sa vad daca nodu 1 e critic
	u[k] = 1;
	low[k] = alt[k];
	vector<int> :: iterator it;
	for (it = con[k].begin(); it != con[k].end(); it++)
	{
		if (!u[*it])
		{
			alt[*it] = alt[k] + 1;
			p[*it] = k;
			push(k, *it);
			dfs(*it);
			NCHILD++;
			if (low[*it] < low[k])
				low[k] = low[*it];
			if (low[*it] >= alt[k])		//nodul k e critic
			{
				art[k] = 1;
				if (k == 1 && NCHILD < 2)
					art[k] = 0;
				popcomp(k, *it);	//extrage componenta biconexa
			}
		}
		else
			if (*it != p[k] && alt[*it] < alt[k])
			{
				push(k, *it);
				if (alt[*it] < low[k])
					low[k] = alt[*it];
			}
	}
}

/*
 * marcheaza componenta biconexa (cur) ca facand parte dintr-un potential drum al piticilor
 */
inline void MARK(int cur)
{
	vector< int > :: iterator it;
	usecomp[cur] = true;
	for (it = compnod[cur].begin(); it != compnod[cur].end(); it++)
		usenod[*it] = true;
}

/*
 * marcheaza nodurile ce trebuie vizitate
 */
queue<int> Q;
int START, END;						//prima si ultima componenta biconexa din drumul piticilor
vector< bool > hasS, hasD, hasQs;

int bfs(int S)
{
	for (; !Q.empty(); Q.pop());

	int i;
	vector< int > :: iterator it;

	memset(u, -1, sizeof(u));
	usenod.clear(); usenod.resize(N + 1, false);
	hasS.resize( compnod.size(), false );
	hasD.resize( compnod.size(), false );
	hasQs.resize( compnod.size(), false );
	for (size_t k = 0; k < compnod.size(); k++)
		for (size_t a = 0; a < compnod[k].size(); a++)
		{
			if (compnod[k][a] == S) hasS[k] = true;
			if (compnod[k][a] == D) hasD[k] = true;
			if (compnod[k][a] == Qs) hasQs[k] = true;
		}
	START = -1;
	for (size_t k = 0; k < compnod.size(); k++)
		if ((hasS[k] && hasQs[k]) || (hasD[k] && hasQs[k]))
		{
			START = k;
			break;
		}

	if (START == -1)
		return 0;
	int foundS, foundD;
	foundS = hasS[START] ? 1 : 0;
	foundD = hasD[START] ? 1 : 0;
	if (foundS && foundD)
	{
		END = START;
		MARK(START);
		return 1;
	}

	for (Q.push(START), u[START] = START; !Q.empty() && (!foundS || !foundD); Q.pop())
	{
		i = Q.front();
		for (size_t k = 0; k < compnod[i].size(); k++)
		{
			int n = compnod[i][k];
			for (it = nodincomp[n].begin(); it != nodincomp[n].end(); it++)
			{
				if (u[*it] != -1)
					continue;

				u[*it] = i;
				Q.push( *it );
				if (!foundD && hasD[*it])
				{
					END = *it;
					foundD = 1;
					break;
				}
				if (!foundS && hasS[*it])
				{
					END = *it;
					foundS = 1;
					break;
				}
			}
		}
	}

	if (!foundS || !foundD)
		return 0;

	for (i = END; i != START; i = u[i])
		MARK(i);
	MARK(START);
	return 1;
}

int main()
{
	freopen("santa.in", "rt", stdin);
//	freopen("santa.out", "wt", stdout);

	scanf("%d %d", &N, &M);
	for (; M; M--)
	{
		int i, j;
		scanf("%d %d", &i, &j);

		con[i].push_back(j);
		con[j].push_back(i);
	}
	scanf("%d %d %d", &S, &D, &Qs);

	dfs(1);					//afla componentele biconexe

/*	for (int i = 1; i <= N; i++)
		if (art[i])
			printf("%d ", i);
	printf("\n");
	for (size_t i = 0; i < compnod.size(); i++)
	{
		for (size_t j = 0; j < compnod[i].size(); j++)
			printf("%d ", compnod[i][j]);
		printf("\n");

		for (size_t j = 0; j < compmuc[i].size(); j++)
			printf("%d %d; ", compmuc[i][j].first, compmuc[i][j].second);
		printf("\n\n");
	}*/

	if (!bfs(S))					//afla toate nodurile care trebuie atinse
	{
		printf("No chance\n");
		return 0;
	}

	int NR = 0;
	for (int i = 1; i <= N; i++)
		if (usenod[i])
		{
//			printf("%d ", i);
			NR++;
		}
//	printf("\n");
	printf("%d\n", NR);

	return 0;
}