http://www.elijahqi.win/2017/07/03/luogu2661/
题目:
有n个同学(编号为1到n)正在玩一个信息传递的游戏。在游戏里每人都有一个固定的信息传递对象,其中,编号为i的同学的信息传递对象是编号为Ti同学。
游戏开始时,每人都只知道自己的生日。之后每一轮中,所有人会同时将自己当前所知的生日信息告诉各自的信息传递对象(注意:可能有人可以从若干人那里获取信息,但是每人只会把信息告诉一个人,即自己的信息传递对象)。当有人从别人口中得知自己的生日时,游戏结束。请问该游戏一共可以进行几轮?
样例输入:
5 2 4 2 3 1
样例输出:
3
说明:
样例1解释
游戏的流程如图所示。当进行完第3轮游戏后,4号玩家会听到2号玩家告诉他自
己的生日,所以答案为3。当然,第3轮游戏后,2号玩家、3号玩家都能从自己的消息
来源得知自己的生日,同样符合游戏结束的条件。
对于 30%的数据, n ≤ 200;
对于 60%的数据, n ≤ 2500;
对于 100%的数据, n ≤ 200000。
强连通
1.tarjan求强连通分量
2.求出分量中>1且是最小的值输出即可
#include<cstdio>
#include<cstring>
using namespace std;
int const N=220000;
struct node{
int x,y,next;
};
int num,stack[N],dfn[N],low[N],h[N],b[N],top,s,n;
bool stackf[N];
node data[N];
void insert1(int x,int y){
data[++num].x=x;
data[num].y=y;
data[num].next=h[x];
h[x]=num;
}
void tarjan(int u){
dfn[u]=++num;
low[u]=num;
stack[++top]=u;
stackf[u]=true;
for (int i=h[u];i;i=data[i].next){
int v=data[i].y;
if (dfn[v]==0){
tarjan(v);
if (low[v]<low[u]) low[u]=low[v];
}else{
if(stackf[v]&&dfn[v]<low[u]) low[u]=dfn[v];
}
}
if (low[u]==dfn[u]){
++s;
int y;
do{
y=stack[top--];
stackf[y]=false;
b[s]++;
}while (y!=u);
}
}
int main(){
freopen("message.in","r",stdin);
freopen("message.out","w",stdout);
scanf("%d",&n);
num=0;
memset(h,0,sizeof(h));
for (int i=1;i<=n;++i){
int t;
scanf("%d",&t);
insert1(i,t);
}
num=top=0;
memset(stackf,false,sizeof(stackf));
memset(dfn,0,sizeof(dfn));
for (int i=1;i<=n;++i){
if (dfn[i]==0) tarjan(i);
}
int min=0x7fffffff;
//printf("%d",b[1]);
//memset(b,0,sizeof(b));
for (int i=1;i<=s;++i){
//printf("%d \n",b[i]);
if (b[i]>1&&(min>b[i])) min=b[i];
}
printf("%d",min);
return 0;
}
程序分析:拓扑排序
强连通计算分量 求大于一的最小值
直接暴力搜环(dfs)
通过拓补排序
#include<cstdio>
#include<cstring>
struct node{
int x,y,next;
};
node data[220000];
bool stackf[220000];
int q[11000],h[220000],aa[220000],a[220000],n,num,min;
void check(int u){
if (stackf[u]==false) return;
int x=data[h[u]].x,y=data[h[u]].y;
stackf[x]=false;
min++;
check(y);
}
int main(){
freopen("message.in","r",stdin);
freopen("message.out","w",stdout);
scanf("%d",&n);
memset(h,0,sizeof(h));
num=0;
memset(aa,0,sizeof(aa));
for (int i=1;i<=n;++i) {
scanf("%d",&a[i]);
aa[a[i]]++;
data[++num].x=i;
data[num].y=a[i];
data[num].next=h[i];
h[i]=num;
}
int op=0,cl=0;
for (int i=1;i<=n;++i)
if (aa[i]==0) {
q[++cl]=i;
}
//拓补排序
while (op<cl){
++op;
if (op==11000) op=0;
for (int i=h[q[op]];i;i=data[i].next){
int x=data[i].x,y=data[i].y;
aa[y]--;
if (aa[y]==0) {
++cl;
if (cl==11000) cl=0;
q[cl]=y;
}
}
}
memset(stackf,true,sizeof(stackf));
int ans=0x7fffffff;
for (int i=1;i<=n;++i){
min=0;
if(aa[i]!=0){
check(i);
}
if (min<ans&&min!=0) ans=min;
}
printf("%d",ans);
return 0;
}