USACO 2015 January Contest Gold T3: Grass Cownoisseur

题目大意

约翰有n块草场,编号1到n,这些草场由若m条单行道相连。奶牛贝西是美味牧草的鉴赏家,她想到达尽可能多的草场去品尝牧草。(1 <= n, m <= 100,000).

贝西总是从1号草场出发,最后回到1号草场。她想经过尽可能多的草场,贝西在通过一个草场时只能吃一次草,但一个草场可以经过多次。因为草场是单行道连接,这给贝西的品鉴工作带来了很大的不便,贝西想偷偷逆向行走一次,但最多只能有一次逆行。问,贝西最多能吃到多少个草场的牧草。

题目分析

观察“在通过一个草场时只能吃一次草,但一个草场可以经过多次”,很明显可以看出我们要把相互可以到达的点缩成一个点,这里用Tarjan实现即可。

 

缩点后建出新图,这时从 点1所在强连通分量 所开始跑一遍最短(长)路即可得出没有“逆行”这个条件时的答案。所得结果即为dis1[N]。

 

考虑如何处理逆行。因为贝西最后要回到1号草场,所以我们不妨再反向建一次边,得出以 点1所在强连通分量 为终点的所有最短(长)路。所得结果即为dis2[N]。

然后我们就可以枚举一个 强连通分量x 通过反边找出它可以逆行一次到达的 强连通分量 y, 然后就可以更新答案了。

 

注意 点1所在强连通分量 在作为起点和终点时都被计算了一次,所以要减掉 点1所在强连通分量 内的点数。

化为代码,就是 ans = max( ans, dis1[now] + dis2[y] - tot[bcc[1]] );

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 const int MAXN=1e5+10;
  4 const int MAXM=1e5+10;
  5 
  6 struct Edge{
  7     int to,nxt;
  8 }oe[MAXM],e1[MAXM],e2[MAXM];
  9 int cnt,cnt1,cnt2;
 10 int head[MAXN],head1[MAXN],head2[MAXN];
 11 inline void add_edge(int u,int v){oe[++cnt].to=v;oe[cnt].nxt=head[u];head[u]=cnt;}
 12 inline void add_edge1(int u,int v){e1[++cnt1].to=v;e1[cnt1].nxt=head1[u];head1[u]=cnt1;}
 13 inline void add_edge2(int u,int v){e2[++cnt2].to=v;e2[cnt2].nxt=head2[u];head2[u]=cnt2;}
 14 
 15 int n,m;
 16 
 17 int col,c[MAXN],bcc[MAXN],tot[MAXN];
 18 int tim,dfn[MAXN],low[MAXN];
 19 int top,st[MAXN];
 20 bool insta[MAXN];
 21 
 22 bool vis[MAXN];
 23 int dis1[MAXN],dis2[MAXN];
 24 inline void Tarjan(int x){
 25     dfn[x]=low[x]=++tim;
 26     st[++top]=x;insta[x]=true;
 27     for(int i=head[x],y;i;i=oe[i].nxt){
 28         y=oe[i].to;
 29         if(!dfn[y]){
 30             Tarjan(y);
 31             low[x]=min(low[x],low[y]);
 32         }
 33         else if(insta[y])
 34             low[x]=min(low[x],low[y]);
 35     }
 36     if(low[x]==dfn[x]){
 37         bcc[x]=++col;insta[x]=false;
 38         tot[col]++;
 39         while(st[top]!=x){
 40             ++tot[col];
 41             insta[st[top]]=false;
 42             bcc[st[top--]]=col;
 43         }
 44         --top;
 45     }
 46 }
 47 
 48 inline void SPFA1(int S){
 49     memset(vis,0,sizeof(vis));
 50     dis1[S]=tot[S];
 51     queue<int> q;
 52     q.push(S);
 53     while(!q.empty()){
 54         int x=q.front();q.pop();
 55         vis[x]=false;
 56         for(int i=head1[x],y;i;i=e1[i].nxt){
 57             y=e1[i].to;
 58             if(dis1[y]<dis1[x]+tot[y]){
 59                 dis1[y]=dis1[x]+tot[y];
 60                 if(!vis[y]){
 61                     q.push(y);
 62                     vis[y]=true;
 63                 }
 64             }
 65         }
 66     }
 67 }
 68 inline void SPFA2(int S){
 69     memset(vis,0,sizeof(vis));
 70     dis2[S]=tot[S];
 71     queue<int> q;
 72     q.push(S);
 73     while(!q.empty()){
 74         int x=q.front();q.pop();
 75         vis[x]=false;
 76         for(int i=head2[x],y;i;i=e2[i].nxt){
 77             y=e2[i].to;
 78             if(dis2[y]<dis2[x]+tot[y]){
 79                 dis2[y]=dis2[x]+tot[y];
 80                 if(!vis[y]){
 81                     q.push(y);
 82                     vis[y]=true;
 83                 }
 84             }
 85         }
 86     }
 87 }
 88 int main(){
 89     scanf("%d%d",&n,&m);
 90     for(int i=1,u,v;i<=m;++i){
 91         scanf("%d%d",&u,&v);
 92         add_edge(u,v);
 93     }
 94     for(int i=1;i<=n;++i)
 95         if(!dfn[i])
 96             Tarjan(i);
 97     for(int x=1;x<=n;++x)
 98         for(int i=head[x],y;i;i=oe[i].nxt){
 99             y=oe[i].to;
100             if(bcc[x]!=bcc[y]){
101                 add_edge1(bcc[x],bcc[y]);
102                 add_edge2(bcc[y],bcc[x]);
103             }
104         }
105     SPFA1(bcc[1]);
106     SPFA2(bcc[1]);
107     int ans=tot[bcc[1]];
108     memset(vis,0,sizeof(vis));
109     for(int i=1;i<=n;++i){
110         if(!vis[bcc[i]]&&dis1[bcc[i]]){
111             int now=bcc[i];
112             vis[now]=1;
113             for(int j=head2[now],y;j;j=e2[j].nxt){
114                 y=e2[j].to;
115                 if(!dis2[y]) continue;
116                 ans=max(ans,dis1[now]+dis2[y]-tot[bcc[1]]);
117             } 
118         }
119     }
120     printf("%d\n",ans);
121     return 0;
122 }

 

posted @ 2019-07-19 15:58  LI_dox  阅读(207)  评论(0编辑  收藏  举报