CSU 1526 Beam me out! 强连通

题目链接:点击打开链接

题意:

给定n个点的有向图(1为起点,n为终点)

下面每两行给出一个点的出度和所连接的下一个点。

第n个点是没有出度的

图是这样的: 1->2, 1->3, 2->3

第一问:

若存在一种方案使得这个人进入一个点后再也不能到达终点则输出 PRISON , 否则输出 PARDON

第二问:

若这个人可以在图里走无穷步则输出UNLIMITED, 否则输出LIMITED

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string>
#include <cmath>
#include <cstring>
#include <queue>
#include <set>
#include <map>
#include <vector>

template <class T>
inline bool rd(T &ret) {
	char c; int sgn;
	if (c = getchar(), c == EOF) return 0;
	while (c != '-' && (c<'0' || c>'9')) c = getchar();
	sgn = (c == '-') ? -1 : 1;
	ret = (c == '-') ? 0 : (c - '0');
	while (c = getchar(), c >= '0'&&c <= '9') ret = ret * 10 + (c - '0');
	ret *= sgn;
	return 1;
}
template <class T>
inline void pt(T x) {
	if (x <0) {
		putchar('-');
		x = -x;
	}
	if (x>9) pt(x / 10);
	putchar(x % 10 + '0');
}
using namespace std;

typedef long long ll;
typedef pair<int, int> pii;
const int N = 50500;
const int inf = 1e8;
//N为最大点数
const int M = 7500000;
//M为最大边数
int n;//n m 为点数和边数

struct Edge{
	int from, to, nex;
	bool sign;//是否为桥
}edge[M];
int head[N], edgenum;
void add(int u, int v){//边的起点和终点
	Edge E = { u, v, head[u], false };
	edge[edgenum] = E;
	head[u] = edgenum++;
}

int DFN[N], Low[N], Stack[N], top, Time; //Low[u]是点集{u点及以u点为根的子树} 中(所有反向弧)能指向的(离根最近的祖先v) 的DFN[v]值(即v点时间戳)
int taj;//连通分支标号,从1开始
int Belong[N];//Belong[i] 表示i点属于的连通分支
bool Instack[N];
vector<int> bcc[N]; //标号从1开始

void tarjan(int u, int fa){
	DFN[u] = Low[u] = ++Time;
	Stack[top++] = u;
	Instack[u] = 1;

	for (int i = head[u]; ~i; i = edge[i].nex){
		int v = edge[i].to;
		if (DFN[v] == -1)
		{
			tarjan(v, u);
			Low[u] = min(Low[u], Low[v]);
			if (DFN[u] < Low[v])
			{
				edge[i].sign = 1;//为割桥
			}
		}
		else if (Instack[v]) Low[u] = min(Low[u], DFN[v]);
	}
	if (Low[u] == DFN[u]){
		int now;
		taj++; bcc[taj].clear();
		do{
			now = Stack[--top];
			Instack[now] = 0;
			Belong[now] = taj;
			bcc[taj].push_back(now);
		} while (now != u);
	}
}

void tarjan_init(int all){
	memset(DFN, -1, sizeof(DFN));
	memset(Instack, 0, sizeof(Instack));
	top = Time = taj = 0;
	for (int i = 1; i <= all; i++)if (DFN[i] == -1)tarjan(i, i); //注意开始点标!!!
}
vector<int>G[N];
int du[N], hehe[N];
bool itself[N];
void suodian(){
	memset(du, 0, sizeof(du));
	for (int i = 1; i <= taj; i++){
		G[i].clear();
		hehe[i] = false;
		for (int j = 0; j < bcc[i].size(); j++)
		if (itself[bcc[i][j]])hehe[i] = true;
	}
	for (int i = 0; i < edgenum; i++){
		int u = Belong[edge[i].from], v = Belong[edge[i].to];
		if (u != v)G[u].push_back(v), du[v]++;
	}
}
void init(){ memset(head, -1, sizeof(head)); edgenum = 0; }
bool vis[N];
int siz, bad;
void bfs(){
	memset(vis, 0, sizeof vis);
	queue<int> q; q.push(Belong[1]);
	vis[Belong[1]] = true;
	siz = 0;
	bad = 0;
	while (!q.empty()){
		int u = q.front(); q.pop();
		//		printf(" --%d\n", u);
		if ((int)bcc[u].size() > 1 || hehe[u])siz++;
		if ((int)G[u].size() == 0){
			if (u != Belong[n])bad++;
		}
		for (int i = 0; i < G[u].size(); i++){
			int v = G[u][i];
			//			printf("  **%d\n", v);
			if (!vis[v]){
				vis[v] = true;
				q.push(v);
			}
		}
	}
}
int main() {
	while (cin >> n){
		init();
		for (int i = 1, num, j; i < n; i++){
			itself[i] = false;
			rd(num); while (num-->0){
				rd(j), add(i, j);
				if (j == i)itself[i] = true;
			}
		}
		itself[n] = false;
		tarjan_init(n);
		suodian();
		//		for(int i = 1; i <= n; i++)printf("%d ", Belong[i]); puts("");
		bfs();
		//		printf("leaf:%d siz:%d\n", leaf, siz);
		if (vis[Belong[n]] && bad == 0) printf("PARDON ");
		else printf("PRISON ");
		!siz ? puts("LIMITED") : puts("UNLIMITED");
	}
	return 0;
}
/*
3
2
1
3

*/


你可能感兴趣的:(CSU 1526 Beam me out! 强连通)