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

问题描述

约翰有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]));
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值