【tarjan+拓扑】BZOJ3887-[Usaco2015 Jan]Grass Cownoisseur
【题目大意】
给一个有向图,然后选一条路径起点终点都为1的路径出来,有一次机会可以沿某条边逆方向走,问最多有多少个点可以被经过?(一个点在路径中无论出现多少正整数次对答案的贡献均为1)
【思路】
首先缩点,对于每一个联通块求出正图和反图中节点1所在的联通块到它的最长节点数。这个用拓扑排序处理一下。
枚举每一条边取反,对于边(u,v),其取反后的距离就等于dis[u所在的联通快]+dis[v所在的联通块]-dis[1所在的联通块](因为会被重复计算不要忘记减去)
我一开始非常脑抽地在想会不会发生这样的情况:本来到u所在的联通块就会经过v,这样不就重复计算点了。要注意缩点之后的图为DAG,如果存在v->u的路径,同时存在u->v的路径,那么必定存在环,矛盾。
【错误点】
写x节点所在的联通块的时候,一直写成x节点。千万不要忘记了col[]。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<vector> 6 #include<stack> 7 #include<queue> 8 using namespace std; 9 const int MAXN=100000+50; 10 vector<int> E[MAXN]; 11 vector<int> tE[MAXN],rtE[MAXN]; 12 stack<int> S; 13 int x[MAXN],y[MAXN]; 14 int instack[MAXN],low[MAXN],dfn[MAXN],col[MAXN],size[MAXN],cnt,colcnt; 15 int dis[MAXN],rdis[MAXN],degree1[MAXN],degree2[MAXN]; 16 int vis[MAXN]; 17 int n,m; 18 19 void Topology1() 20 { 21 memset(dis,0xef,sizeof(dis));//初始化为-INF 22 queue<int> que; 23 dis[col[1]]=size[col[1]]; 24 for (int i=1;i<=colcnt;i++) 25 if (!degree1[i]) que.push(i); 26 while (!que.empty()) 27 { 28 int now=que.front();que.pop(); 29 for (int i=0;i<tE[now].size();i++) 30 { 31 int to=tE[now][i]; 32 dis[to]=max(dis[to],dis[now]+size[to]); 33 if (!--degree1[to]) que.push(to); 34 } 35 } 36 } 37 38 void Topology2() 39 { 40 memset(rdis,0xef,sizeof(rdis)); 41 queue<int> que; 42 rdis[col[1]]=size[col[1]]; 43 for (int i=1;i<=colcnt;i++) 44 if (!degree2[i]) que.push(i); 45 while (!que.empty()) 46 { 47 int now=que.front();que.pop(); 48 for (int i=0;i<rtE[now].size();i++) 49 { 50 int to=rtE[now][i]; 51 rdis[to]=max(rdis[to],rdis[now]+size[to]); 52 if (!--degree2[to]) que.push(to); 53 } 54 } 55 } 56 57 58 void tarjan(int u) 59 { 60 dfn[u]=low[u]=++cnt; 61 instack[u]=1; 62 S.push(u); 63 for (int i=0;i<E[u].size();i++) 64 { 65 int v=E[u][i]; 66 if (!instack[v]) 67 { 68 tarjan(v); 69 low[u]=min(low[u],low[v]); 70 71 } 72 else if (instack[v]==1) low[u]=min(low[u],dfn[v]); 73 } 74 75 if (dfn[u]==low[u]) 76 { 77 colcnt++; 78 int x; 79 do 80 { 81 x=S.top(); 82 col[x]=colcnt; 83 instack[x]=2; 84 size[colcnt]++; 85 S.pop(); 86 }while (x!=u); 87 } 88 } 89 90 void init() 91 { 92 scanf("%d%d",&n,&m); 93 for (int i=0;i<m;i++) 94 { 95 scanf("%d%d",&x[i],&y[i]); 96 E[x[i]].push_back(y[i]); 97 } 98 memset(instack,0,sizeof(instack)); 99 cnt=colcnt=0; 100 for (int i=1;i<=n;i++) 101 if (!instack[i]) tarjan(i); 102 for (int i=0;i<m;i++) 103 { 104 if (col[x[i]]!=col[y[i]]) 105 { 106 tE[col[x[i]]].push_back(col[y[i]]); 107 degree1[col[y[i]]]++; 108 rtE[col[y[i]]].push_back(col[x[i]]); 109 degree2[col[x[i]]]++; 110 } 111 } 112 } 113 114 void solve() 115 { 116 memset(dis,0,sizeof(dis)); 117 memset(rdis,0,sizeof(rdis)); 118 Topology1(); 119 Topology2(); 120 int ans=-1; 121 for (int i=0;i<m;i++) 122 { 123 ans=max(ans,dis[col[x[i]]]+rdis[col[y[i]]]);//注意这里是col[x[i]]不要写成x[i]了 124 ans=max(ans,rdis[col[x[i]]]+dis[col[y[i]]]); 125 } 126 printf("%d",ans-size[1]); 127 } 128 129 int main() 130 { 131 init(); 132 solve(); 133 return 0; 134 }