zoukankan      html  css  js  c++  java
  • 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
    ",ans);
    121     return 0;
    122 }
  • 相关阅读:
    JAVA实验3 类与对象
    多种排序功能的实现
    (数据结构)HashTable的实现
    对string型变量的频率统计(文章单词检索)
    对int型变量的频率统计
    二叉搜索树中序迭代器的实现
    二叉搜索树的实现
    Prim最小生成树
    Kruscal最小生成树
    算法分析实践大作业
  • 原文地址:https://www.cnblogs.com/LI-dox/p/11213810.html
Copyright © 2011-2022 走看看