题目链接:点击打开链接
题意:
给定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
*/