zoukankan      html  css  js  c++  java
  • 洛谷P3119 草鉴定

    这个题调了一天。。

    传送门

    读完题目之后我们不难想出这个题是个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;
    }
    顺风不浪,逆风不怂。
  • 相关阅读:
    linux防止sshd被爆破(安装denyhosts)
    记一次网站服务器搬迁实录
    用几条shell命令快速去重10G数据
    如何让你的scrapy爬虫不再被ban之二(利用第三方平台crawlera做scrapy爬虫防屏蔽)
    同时运行多个scrapy爬虫的几种方法(自定义scrapy项目命令)
    如何让你的scrapy爬虫不再被ban
    scrapy爬虫成长日记之将抓取内容写入mysql数据库
    scrapy爬虫成长日记之创建工程-抽取数据-保存为json格式的数据
    python将json格式的数据转换成文本格式的数据或sql文件
    shell脚本去重的几种方法
  • 原文地址:https://www.cnblogs.com/Stephen-F/p/9864613.html
Copyright © 2011-2022 走看看