洛谷 P3119 [USACO15JAN]草鉴定Grass Cownoisseur

洛谷 P3119 [USACO15JAN]草鉴定Grass Cownoisseur

Description

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

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

Input

  • 第一行:草场数n,道路数m。

    以下m行,每行x和y表明有x到y的单向边,不会有重复的道路出现。

Output

  • 一个数,逆行一次最多可以走几个草场。

Sample Input

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

Sample Output

6

题解:

  • tarjan + 分层图。
  • 首先有可能有环所以缩点基操。问题是处理逆行一次。可以建两层图。如有一条u -> v的边,先add(u, v),再add(u + n, v + n),再add(v + n, u)表示逆行。
  • 然后跑最长路输出dis[1 + n]即可
#include 
#include 
#include 
#include 
#include 
#define N 500005
using namespace std;

queue que;
stack stk;
struct E {int next, to;} e[N];
int n, m, num, dex, tot;
int h[N], u[N], v[N], dfn[N], low[N], bel[N], val[N], dis[N];
bool vis[N];

int read()
{
    int x = 0; char c = getchar();
    while(c < '0' || c > '9') c = getchar();
    while(c >= '0' && c <= '9') {x = x * 10 + c - '0'; c = getchar();}
    return x;
}

void add(int u, int v)
{
    e[++num].next = h[u];
    e[num].to = v;
    h[u] = num;
}

void tarjan(int x)
{
    dfn[x] = low[x] = ++dex;
    stk.push(x), vis[x] = 1;
    for(int i = h[x]; i != 0; i = e[i].next)
        if(!dfn[e[i].to])
            tarjan(e[i].to),
            low[x] = min(low[e[i].to], low[x]);
        else if(vis[e[i].to])
            low[x] = min(low[x], dfn[e[i].to]);
    if(dfn[x] == low[x]) {
        tot++;
        while(1)
        {
            int now = stk.top();
            stk.pop(), vis[now] = 0;
            bel[now] = tot;
            val[tot]++;
            if(x == now) break;
        }
    }
}

int main()
{
    cin >> n >> m;
    for(int i = 1; i <= m; i++)
    {
        u[i] = read(), v[i] = read();
        add(u[i], v[i]);
    }
    for(int i = 1; i <= n; i++)
        if(!dfn[i]) tarjan(i);
    num = 0;
    memset(h, 0, sizeof(h));
    memset(vis, 0, sizeof(vis));
    for(int i = 1; i <= tot; i++)
        val[i + tot] = val[i];
    for(int i = 1; i <= m; i++)
        if(bel[u[i]] != bel[v[i]])
        {
            int x = bel[u[i]], y = bel[v[i]];
            add(x, y);
            add(x + tot, y + tot);
            add(y, x + tot);
        }
    que.push(bel[1]);
    vis[bel[1]] = 1;
    //这里不加dis[bel[1]] = val[1]是因为bel[1]要走两遍
    while(que.size())
    {
        int now = que.front();
        que.pop(), vis[now] = 0;
        for(int i = h[now]; i != 0; i = e[i].next)
            if(dis[now] + val[now] > dis[e[i].to])
            {
                dis[e[i].to] = dis[now] + val[now];
                if(!vis[e[i].to]) que.push(e[i].to);
            }
    }
    cout << dis[bel[1] + tot];
    return 0;
}

你可能感兴趣的:(洛谷 P3119 [USACO15JAN]草鉴定Grass Cownoisseur)