【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 }
原文地址:https://www.cnblogs.com/iiyiyi/p/5911107.html