题意:如果从一个点出发所能到达的所有点,反过来都能到达这个出发点,那么这个出发点称为sink点。输出所有sink点
思路:求出所有的极大强连通分支。因为强连通子图可能有指向其他强连通子图的单向边,所以有指向其他强连通子图的点都不要(因为指向其他子图,对应被指向的子图无法回到出发的子图(否则已是同一个强连通)
Source Code
Problem: 2553 User: nd096040177
Memory: 2356K Time: 141MS
Language: C++ Result: Accepted
Source Code
#include<iostream>
#include<stack>
using namespace std;
struct Node
{
int value;
struct Node *next;
}node[5001],*p;
bool Visited[5001],IsInstack[5001],NewOut[5001];
bool IsPrint[5001];
int dfn[5001],low[5001],belong[5001],nTime;
int N,PN,nSet;
stack <int> Q;
//添加顶点
void AddNode(int root,int tnode)
{
p=new struct Node;
p->value=tnode;
p->next=node[root].next;
node[root].next=p;
}
int min(int tx,int ty)
{
if(tx>ty) return ty;
else return tx;
}
void init()
{
int i,x,y;
scanf("%d",&PN);
for(i=1;i<=N;i++)//初始化图
node[i].next=NULL;
for(i=0;i<PN;i++)//绘图
{
scanf("%d%d",&x,&y);
AddNode(x,y);
}
memset(Visited,false,sizeof(Visited));
memset(IsInstack,false,sizeof(IsInstack));
memset(NewOut,false,sizeof(NewOut));
memset(IsPrint,false,sizeof(IsPrint));
nTime=nSet=0;
while(!Q.empty())//清空栈
Q.pop();
}
void Tarjan(int t)
{
dfn[t]=low[t]=++nTime;
Visited[t]=true;
Q.push(t);//入栈
IsInstack[t]=true;
struct Node *q;
int x;
for(q=node[t].next;q!=NULL;q=q->next)
{
x=q->value;
if(!Visited[x])
{
Tarjan(x);
low[t]=min(low[t],low[x]);
}
else if(IsInstack[q->value])
low[t]=min(low[t],dfn[q->value]);
}
if(dfn[t]==low[t])//找到一个强连通
{
nSet++;
int k;
do
{
k=Q.top();
IsInstack[k]=false;
belong[k]=nSet;
Q.pop();
}while(k!=t);
}
}
void doit()
{
int i;
for(i=1;i<=N;i++)
{
if(!Visited[i])
Tarjan(i);
}
//NewOut
struct Node *q;
for(i=1;i<=N;i++)
{
for(q=node[i].next;q!=NULL;q=q->next)
{
if(belong[i]!=belong[q->value])
{
NewOut[belong[i]]=true;
break;
}
}
}
for(i=1;i<=N;i++)
{
if(!NewOut[belong[i]])
IsPrint[i]=true;
}
//将bottom类输出
int first=true;
for(i=1;i<=N;i++)
{
if(IsPrint[i])
{
if(first)
{
printf("%d",i);
first=false;
}
else printf(" %d",i);
}
}
printf("\n");
}
int main()
{
while(scanf("%d",&N)&&N)
{
init();
doit();
}
return 0;
}