P3213【USACO 2015 Jan Gold】牧草鉴赏家

来源:互联网 发布:知乎 性观念 编辑:程序博客网 时间:2024/05/01 05:32

问题描述

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

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

输入格式

第一行,两个整数N和M(1<=N,M<=100000)
接下来M行,表示有M条单向道路,每条道路有连个整数X和Y表示,从X出发到达Y。

输出格式

一个整数,表示所求答案

样例输入

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

样例输出

6

提示

贝西的行走线路是1, 2, 4, 7, 2, 5, 3, 1 ,在5到3的时候逆行了一次。

题解

tarjan缩点然后用spfa跑分层图最长路或是用top排序dp求最长链

代码

#include<stdio.h>#include<iostream>#include<cstdio>#include<algorithm>#include<cmath>#include<cstring>#include<queue>#include<stack>using namespace std;#define maxn1 100005#define pr cout<<struct node{    int x,k;};int Last[maxn1],Next[maxn1],End[maxn1],St[maxn1];int Last1[maxn1],Next1[maxn1],End1[maxn1],Len[maxn1];int Last2[maxn1],Next2[maxn1],End2[maxn1],Len2[maxn1];int cnt,scc,vis;int dfn[maxn1],low[maxn1];int be[maxn1],p[maxn1];int n,m;bool mark[maxn1][2],instack[maxn1];stack<int>s;queue<node>q;int dis[maxn1][2];void spfa(){    int i,j;    node t;    t.x=be[1];t.k=0;    q.push(t);    mark[t.x][t.k]=true;    while(q.size())    {        node tmp=q.front();        q.pop();        mark[tmp.x][tmp.k]=false;        int st=tmp.x;        int k1=tmp.k;        for(i=Last1[st];i;i=Next1[i])        {            int en=End1[i];//          pr st<<"->"<<en<<" ";            if(dis[en][k1]<dis[st][k1]+Len[i])            {                dis[en][k1]=dis[st][k1]+Len[i];                if(mark[en][k1]==false){                    node tt;                    tt.x=en;                    tt.k=k1;                    q.push(tt);                    mark[en][k1]=true;                }            }        }        if(k1==0)        {            for(i=Last2[st];i;i=Next2[i])        {            int en=End2[i];            if(dis[en][1]<dis[st][0]+Len2[i])            {                dis[en][1]=dis[st][0]+Len2[i];                if(mark[en][1]==false){                    node tt;                    tt.x=en;tt.k=1;                    q.push(tt);                    mark[en][1]=true;                }            }        }        }    }}void tj(int x){    int i;    dfn[x]=low[x]=++vis;    s.push(x);instack[x]=true;    for(i=Last[x];i;i=Next[i])    {        int en=End[i];        if(dfn[en]==false)        {            tj(en);            low[x]=min(low[x],low[en]);        }        else if(instack[en])        {            low[x]=min(low[x],dfn[en]);        }    }    if(dfn[x]==low[x]){       scc++;       int t;       do{          t=s.top();          s.pop();instack[t]=false;          be[t]=scc;          p[scc]++;       }while(t!=x);    }}void insert(int x,int y){    cnt++;    St[cnt]=x;    Next[cnt]=Last[x];    Last[x]=cnt;    End[cnt]=y;}void insert1(int x,int y,int z,int z1){    cnt++;    Next1[cnt]=Last1[x];    Last1[x]=cnt;    End1[cnt]=y;    Len[cnt]=z;    Next2[cnt]=Last2[y];    Last2[y]=cnt;    End2[cnt]=x;    Len2[cnt]=z1;}int main(){    int i,j;//  freopen("taste.in","r",stdin);//  freopen("taste.out","w",stdout);    scanf("%d%d",&n,&m);    for(i=1;i<=m;i++)    {        int x,y;        scanf("%d%d",&x,&y);        insert(x,y);    }    cnt=0;    for(i=1;i<=n;i++) if(dfn[i]==0) tj(i);//  for(i=1;i<=scc;i++) pr p[i];    for(i=1;i<=m;i++){        int x=St[i],y=End[i];        if(be[x]!=be[y])        {            insert1(be[x],be[y],p[be[y]],p[be[x]]);        }    }//  for(i=1;i<=n;i++) pr be[i];    spfa();    cout<<max(p[be[1]],max(dis[be[1]][1],dis[be[1]][0]));}
阅读全文
0 0