草鉴定

Posted stephen-f

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了草鉴定相关的知识,希望对你有一定的参考价值。

这个题调了一天。。

传送门

读完题目之后我们不难想出这个题是个tarjan缩点问题,因为尽量多的经过草场,所以一号点所在的强连通分量里左右的点都是不需要在进行走逆向边,所能到达的。

然后问题就落在怎么处理我们走这一次逆向边上。

仔细看题目要求,题目要求我们必须从一号点出发,最后回到一号点。所以我想到了建一个逆向的图,虚拟出cnt + 1 , cnt+2,cnt+3.....n+cnt号点,建一个逆向图(用进行缩点之后的点集重新构造),因为我们求出进过草场最多是多少,所以我们将强连通分量中有多少个点在缩点中记录下来(num[i]:表示第ii个强连通分量中有多少个点),将它作为边权。

最后我们只要从1号点所在的强连通分量开始,跑一边最长路就好了,最后输出从1号点到我们虚拟出来的1 + cnt号点就好了。

 

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
const int maxn = 2e5 + 5;

inline int read(){
    char ch = getchar();
    int f = 1 , x = 0;
    while(ch > 9 || ch < 0){if(ch == -)f = -1;ch = getchar();}
    while(ch >= 0 && ch <= 9){x = (x << 1) + (x << 3) + ch - 0;ch = getchar();}
    return x * f;
}

int n,m,x,y;
int head[maxn],tot,head2[maxn],tot2;
int ans;

struct Edge{
    int from,to,next;
}edge[maxn << 1],edge2[maxn << 1]; 

void add(int u,int v){
    edge[++tot].from = u;
    edge[tot].to = v;
    edge[tot].next = head[u];
    head[u] = tot;
}

void add_edge(int u,int v){
    edge2[++tot2].from = u;
    edge2[tot2].to = v;
    edge2[tot2].next = head2[u];
    head2[u] = tot2;
}

int dfn[maxn],low[maxn],ind;
int belong[maxn],num[maxn],cnt,stack[maxn],top;
bool ins[maxn];

void tarjan(int x){
    low[x] = dfn[x] = ++ind;
    ins[x] = true;
    stack[++top] = x;
    for(int i=head[x];i;i=edge[i].next){
        int v = edge[i].to;
        if(ins[v])  low[x] = min(low[x] , dfn[v]);
        if(!dfn[v]) {
            tarjan(v);
            low[x] = min(low[x] , low[v]);
        } 
    }
    int k = 0;
    if(dfn[x] == low[x]){
        cnt++;
        do{
            k = stack[top];
            num[cnt]++;
            top--;
            ins[k] = false;
            belong[k] = cnt;
        }  while(k != x);
    }
}

int dis[maxn];
bool vis[maxn];

void spfa(int s){
    queue<int> q;
    q.push(s);
    dis[s] = 0;
    vis[s] = true;
    while(!q.empty()){
        int cur = q.front();
        q.pop();  vis[cur] = false;
        for(int i=head2[cur];i;i=edge2[i].next){
            int v = edge2[i].to;
            if(dis[v] < dis[cur] + num[cur]){
                dis[v] = dis[cur] + num[cur];
                if(vis[v] == 0){
                    q.push(v);
                    vis[v] = true;
                }
            }
        }
    }
}

int main(){
    n = read(); m = read();
    for(int i=1;i<=m;i++){
        x = read(); y =read();
        add(x , y);
    }
    for(int i=1;i<=n;i++)
       if(!dfn[i])  tarjan(i);
    for(int i=1;i<=n;i++)
       num[i + cnt] = num[i];
    for(int i=1;i<=m;i++)
        if(belong[edge[i].from] != belong[edge[i].to]){
            add_edge(belong[edge[i].from] , belong[edge[i].to]);
            add_edge(belong[edge[i].to] , belong[edge[i].from] + cnt);
            add_edge(belong[edge[i].from] + cnt , belong[edge[i].to] + cnt);
        }
    spfa(belong[1]);
    printf("%d
",dis[belong[1] + cnt]);
    return 0;
}

 

以上是关于草鉴定的主要内容,如果未能解决你的问题,请参考以下文章

P3119 [USACO15JAN]草鉴定Grass Cownoisseur

[USACO15JAN]草鉴定Grass Cownoisseur(分层图+tarjan)

[USACO15JAN]草鉴定Grass Cownoisseur

洛谷——P3119 [USACO15JAN]草鉴定Grass Cownoisseur

草鉴定

洛谷 P3119 [USACO15JAN]草鉴定Grass Cownoisseur