POJ_2553
这个题目本来是比较容易下手的,最后只需要求所有出度为0的强连通分量所包含的点,然后按字典序输出即可。但是由于一开始用邻接表写代码的时候由于读入边和存储边的写法问题导致我一直TLE,后来终于知道了怎么写才不会TLE,但是还是不太懂其中的原理,听群里人说是因为TLE的写法翻译成汇编语言会多出很多语句。
因此,以后写代码的时候,还是尽量少在数组名里面再嵌套数组名。
同时看了别人的代码还有一些额外的收获,就是在用邻接矩阵储存无权边时,用bool数组要比int的效率高,数据多时,即使在C里面用char数组都要比int数组的效率有明显的提高(大概20%,当然只是针对这个题目而言)。
#include<stdio.h>
#include<string.h>
int first[5010],next[25000010],v[5010];
int num,output[5010];
int s[5010],ins[5010],top,time,dfn[5010],low[5010],paint[5010];
void tarjan(int a)
{
int e,b,temp;
dfn[a]=low[a]=++time;
s[top++]=a;
ins[a]=1;
for(e=first[a];e!=-1;e=next[e])
{
b=v[e];
if(!dfn[b])
{
tarjan(b);
if(low[b]<low[a])
low[a]=low[b];
}
else if(ins[b]&&dfn[b]<low[a])
low[a]=dfn[b];
}
if(dfn[a]==low[a])
{
s[top]=-1;
while(s[top]!=a)
{
temp=s[--top];
ins[temp]=0;
paint[temp]=num;
}
num++;
}
}
int main()
{
int i,j,V,E,e,a,count;
while(1)
{
scanf("%d",&V);
if(V==0)
break;
scanf("%d",&E);
for(i=1;i<=V;i++)
{
first[i]=-1;
dfn[i]=0;
ins[i]=0;
}
for(e=0;e<E;e++)
{
scanf("%d%d",&a,&v[e]);
next[e]=first[a];
first[a]=e;
}
top=time=num=0;
for(a=1;a<=V;a++)
if(!dfn[a])
tarjan(a);
for(i=0;i<num;i++)
output[i]=1;
for(i=1;i<=V;i++)
for(j=first[i];j!=-1;j=next[j])
if(paint[i]!=paint[v[j]])
output[paint[i]]=0;
for(j=1;;j++)
if(output[paint[j]])
{
printf("%d",j);
break;
}
for(j+=1;j<=V;j++)
if(output[paint[j]])
printf(" %d",j);
printf("\n");
}
return 0;
}