题目链接http://www.lydsy.com/JudgeOnline/problem.php?id=3887
Description
给一个有向图,然后选一条路径起点终点都为1的路径出来,有一次机会可以沿某条边逆方向走,问最多有多少个点可以被经过?(一个点在路径中无论出现多少正整数次对答案的贡献均为1)
Sample Input
7 10
1 2
3 1
2 5
2 4
3 7
3 5
3 6
6 5
7 2
4 7
Sample Output
6
边是可以重复的,则对于每个强连通分量,如果一个点可以被走到,则所有的点一定都可以被走到
如果我们没有逆着某条边走的机会,那么答案就是
1
所在的强连通分量
而现在我们有这个机会,如果将一条边
所以可以在Tarjan缩完点后按拓扑序分别求出
1
到每个点
最后枚举每一条边,计算一下将该边反置的答案就
OK
了
代码如下:
#include<cstdio>
#define N 100020
using namespace std;
char xB[1<<15],*xS=xB,*xTT=xB;
#define getc() (xS==xTT&&(xTT=(xS=xB)+fread(xB,1,1<<15,stdin),xS==xTT)?0:*xS++)
#define isd(c) (c>='0'&&c<='9')
inline int min(int a,int b){if(a<b) return a;return b;}
inline int max(int a,int b){if(a>b) return a;return b;}
inline int read(){
register int x=0; char c;
do {c=getc();} while(!isd(c));
do x=(x<<3)+(x<<1)+c-'0',c=getc(); while(isd(c));
return x;
}
struct Edge{
int to,nex;
Edge(int _=0,int __=0):to(_),nex(__){}
}nex[N],nex1[N],Nex[N];
int q[N];
bool b[N];
int fir[N],fir1[N],Fir[N],cd[N],cd1[N];
int f[N],f1[N];
int dfn[N],low[N],s[N],belong[N],size[N];
int n,m,x,y,v,top,top1,Top,scc_cnt,T,ans;
inline bool add(int x,int y,int &top,int fir[],Edge nex[]){
nex[++top]=Edge(y,fir[x]);
fir[x]=top;
}
void Tarjan(int x){
dfn[x]=low[x]=++T;s[++top]=x;
b[x]=true;
register int i;
for(i=Fir[x];i;i=Nex[i].nex){
if(!dfn[Nex[i].to]){
Tarjan(Nex[i].to);
low[x]=min(low[x],low[Nex[i].to]);
}
else if(b[Nex[i].to]) low[x]=min(low[x],low[Nex[i].to]);
}
if(dfn[x]==low[x]){
scc_cnt++;
do{
v=s[top--];
belong[v]=scc_cnt;
size[scc_cnt]++;
b[v]=false;
}while(v!=x);
}
}
inline void Toposort(int fir[],Edge nex[],int cd[],int f[]){
register int i,l,r;
l=1;r=0;
for(i=1;i<=scc_cnt;i++){
if(!cd[i]) q[++r]=i;
f[i]=-2147483647;
}
f[belong[1]]=size[belong[1]];
while(l<=r){
int x=q[l++];
for(i=fir[x];i;i=nex[i].nex){
f[nex[i].to]=max(f[x]+size[nex[i].to],f[nex[i].to]);
cd[nex[i].to]--;
if(!cd[nex[i].to]) q[++r]=nex[i].to;
}
}
}
main(){
n=read();m=read();
register int i,j;
for(i=1;i<=m;i++){
x=read();y=read();
add(x,y,Top,Fir,Nex);
}
top=0;
for(i=1;i<=n;i++)
if(!dfn[i]){
Tarjan(i);
top=0;
}
top=0;
for(i=1;i<=n;i++)
for(j=Fir[i];j;j=Nex[j].nex){
if(belong[i]==belong[Nex[j].to]) continue;
add(belong[Nex[j].to],belong[i],top,fir,nex); cd[belong[i]]++;
add(belong[i],belong[Nex[j].to],top1,fir1,nex1); cd1[belong[Nex[j].to]]++;
}
Toposort(fir,nex,cd,f);
Toposort(fir1,nex1,cd1,f1);
ans=size[belong[1]]<<1;
for(i=1;i<=n;i++)
for(j=Fir[i];j;j=Nex[j].nex){
if(f1[belong[Nex[j].to]]>=0 && f[belong[i]]>=0)//-INF+-INF
ans=max(ans,f1[belong[Nex[j].to]]+f[belong[i]]);
}
printf("%d",ans-size[belong[1]]);
return 0;
}
总结:
①-INF+-INF得正的
②register好快啊
③STL就是垃圾
④三位运算符贼慢
⑤cyk好神啊

本文探讨了一道关于有向图的算法题,目标是在给定条件下寻找包含最多节点的路径,允许一次反向行走。文章详细介绍了使用Tarjan算法进行强连通分量分解的方法,并通过拓扑排序计算最远距离。
430

被折叠的 条评论
为什么被折叠?



