真正的危机不是机器人像人一样思考,而是人像机器一样思考。 ——凉宫春日的忧郁

[补档][Usaco2015 Jan]Grass Cownoisseur

[Usaco2015 Jan]Grass Cownoisseur

题目

给一个有向图,然后选一条路径起点终点都为1的路径出来,有一次机会可以沿某条边逆方向走,问最多有多少个点可以被经过?
(一个点在路径中无论出现多少正整数次对答案的贡献均为1)

INPUT

The first line of input contains N and M, giving the number of fields and the number of one-way paths (1 <= N, M <= 100,000). The following M lines each describe a one-way cow path. Each line contains two distinct field numbers X and Y, corresponding to a cow path from X to Y. The same cow path will never appear more than once.
N个点,M条有向边,无重边

OUTPUT

A single line indicating the maximum number of distinct fields Bessie
can visit along a route starting and ending at field 1, given that she can
follow at most one path along this route in the wrong direction.

SAMPLE

INPUT

7 10
1 2
3 1
2 5
2 4
3 7
3 5
3 6
6 5
7 2
4 7

OUTPUT

6

解题报告

这道题考试的时候,一看就知道是tarjan,然后就真的傻傻的打了个tarjan+dfs,就A了一个点= =
正解:
tarjan缩点,因为可以逆转一条边,而同一强连通分量里的边逆转是没啥用的,所以我们可以枚举缩点后的边。
首先,跑2遍SPFA,一遍缩点后的正边,一遍反边,处理出正反两个最大的经过权值(每点权值为缩点后强连通分量的点数)。
剩下的就很简单了,思考当一条有向边反过来时,它反边的起点走的是正向的最大权值,而终点则走的是反向的最大权值,那么我们枚举每一条边,两权相加求max即为答案。
注意:特判,两边SPFA若有一遍没有联通这条边对应的强连通分量,这个点就不能跑。
  1 #include<iostream>
  2 #include<cstring>
  3 #include<cstdio>
  4 #include<queue>
  5 using namespace std;
  6 inline int read(){
  7     int sum(0);
  8     char ch(getchar());
  9     while(ch<'0'||ch>'9')
 10         ch=getchar();
 11     while(ch>='0'&&ch<='9'){
 12         sum=sum*10+ch-'0';
 13         ch=getchar();
 14     }
 15     return sum;
 16 }
 17 struct edge{
 18     int s,e,n;
 19 }k[100001],a[100001],b[100001];
 20 int pre[100001],tot;
 21 inline void insert(int s,int e){
 22     k[++tot].s=s;
 23     k[tot].e=e;
 24     k[tot].n=pre[s];
 25     pre[s]=tot;
 26 }
 27 int low[100001],dfn[100001],stack[100001],bl[100001],size[100001];
 28 int head,cnt,qlt;
 29 bool vis[100001];
 30 inline int my_min(int a,int b){
 31     return a<b?a:b;
 32 }
 33 inline int my_max(int a,int b){
 34     return a>b?a:b;
 35 }
 36 inline void tarjan(int u){
 37     low[u]=dfn[u]=++cnt;
 38     vis[u]=1;
 39     stack[++head]=u;
 40     for(int i=pre[u];i!=-1;i=k[i].n){
 41         int e(k[i].e);
 42         if(!dfn[e]){
 43             tarjan(e);
 44             low[u]=my_min(low[u],low[e]);
 45         }
 46         else
 47             if(vis[e])
 48                 low[u]=my_min(low[u],dfn[e]);
 49     }
 50     if(low[u]==dfn[u]){
 51         int tmp;
 52         qlt++;
 53         while(1){
 54             tmp=stack[head--];
 55             bl[tmp]=qlt;
 56             vis[tmp]=0;
 57             if(tmp==u)
 58                 break;
 59         }
 60     }
 61 }
 62 int adj[100001],num;
 63 inline void add(int s,int e){
 64     a[++num].s=s;
 65     a[num].e=e;
 66     a[num].n=adj[s];
 67     adj[s]=num;
 68 }
 69 queue<int>q;
 70 int fz[100001];
 71 inline void spfa1(int x){
 72     memset(vis,0,sizeof(vis));
 73     memset(fz,0,sizeof(fz));
 74     q.push(x);
 75     fz[x]=size[x];
 76     vis[x]=1;
 77     while(!q.empty()){
 78         int k(q.front());
 79         q.pop();
 80         for(int i=adj[k];i!=-1;i=a[i].n){
 81             int e(a[i].e);
 82             if(fz[e]<fz[k]+size[e]){
 83                 fz[e]=fz[k]+size[e];
 84                 if(!vis[e]){
 85                     q.push(e);
 86                     vis[e]=1;
 87                 }
 88             }
 89         }
 90         vis[k]=0;
 91     }
 92 }
 93 int hhh,nxt[100001];
 94 inline void init(int s,int e){
 95     b[++hhh].s=s;
 96     b[hhh].e=e;
 97     b[hhh].n=nxt[s];
 98     nxt[s]=hhh;
 99 }
100 int ff[100001];
101 inline void spfa2(int x){
102     memset(vis,0,sizeof(vis));
103     memset(ff,0,sizeof(ff));
104     q.push(x);
105     ff[x]=size[x];
106     vis[x]=1;
107     while(!q.empty()){
108         int k(q.front());
109         q.pop();
110         for(int i=nxt[k];i!=-1;i=b[i].n){
111             int e(b[i].e);
112             if(ff[e]<ff[k]+size[e]){
113                 ff[e]=ff[k]+size[e];
114                 if(!vis[e]){
115                     q.push(e);
116                     vis[e]=1;
117                 }
118             }
119         }
120         vis[k]=0;
121     }
122 }
123 inline int find(int x){
124     int s(a[x].e),e(a[x].s);
125     if(!fz[s]||!ff[e])
126         return 0;
127     return fz[s]+ff[e]-size[bl[1]];
128 }
129 int n,m;
130 int main(){
131     memset(pre,-1,sizeof(pre));
132     memset(adj,-1,sizeof(adj));
133     memset(nxt,-1,sizeof(nxt));
134     n=read(),m=read();
135     for(int i=1;i<=m;i++){
136         int x(read()),y(read());
137         insert(x,y);
138     }
139     for(int i=1;i<=n;i++)
140         if(!dfn[i])
141             tarjan(i);
142     for(int i=1;i<=n;i++)
143         size[bl[i]]++;
144     for(int i=1;i<=tot;i++){
145         int s(k[i].s),e(k[i].e);
146         if(bl[s]!=bl[e])
147             add(bl[s],bl[e]),init(bl[e],bl[s]);
148     }
149     spfa1(bl[1]);
150     spfa2(bl[1]);
151     int ans(0);
152     for(int i=1;i<=num;i++)
153         ans=my_max(ans,find(i));
154     printf("%d\n",ans);
155 }
View Code
ps:调了我两个小时,最后发现重新建边的时候我用的原来点的编号,没有用缩完点后的编号,然后就听取蛙声一片了= =
posted @ 2017-08-02 20:41  Hzoi_Mafia  阅读(165)  评论(0编辑  收藏  举报
我们都在命运之湖上荡舟划桨,波浪起伏着而我们无法逃脱孤航。但是假使我们迷失了方向,波浪将指引我们穿越另一天的曙光。 ——死神