zoukankan      html  css  js  c++  java
  • P3119 [USACO15JAN]Grass Cownoisseur G

    P3119 [USACO15JAN]Grass Cownoisseur G
    tarjan缩点+分层图上跑 spfa最长路

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

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


    #include<cstdio>
    #include<utility>
    #include<algorithm>
    #include<iostream>
    #include<cmath>
    #include<map>
    #include<iomanip>
    #include<queue>
    #include<cstring>
    #define reg register
    #define EN std::puts("")
    #define LL long long
    inline int read(){
    	register int x=0;register int y=1;
    	register char c=std::getchar();
    	while(c<'0'||c>'9'){if(c=='-') y=0;c=std::getchar();}
    	while(c>='0'&&c<='9'){x=x*10+(c^48);c=std::getchar();}
    	return y?x:-x;
    }
    //P3119 [USACO15JAN]Grass Cownoisseur G
    //https://www.luogu.com.cn/problem/P3119 
    //分层图 +tarjan+spfa 最长路 
    //分层图,第一层是( 1~n )没用过逆着走的机会的,第二层( n+1~2*n )是用过的,两层之间连反向边 
    //不过要缩点以后再分层,不然缩点的时候就是分层的可能就缩乱了 
    //一开始直接连玩分层图再跑最长路,那样似乎并不行 
    
    //然而,这样分层跑最长路的时候,并不会出现重复计算的情况
    //下面讨论的 u,v,w 等,都是指的缩完点后的一个强连通分量,而不是单纯的一个点
    //说的 1,其实也是指的 1 所在的强连通分量,只不过这样描述起来更简便而已
     
    //比如我从 u 走到了 v,然后从 v 通过一个反向边回到了它的上一个节点,设其为 w 
    //然后再通过 w 走回了 u
    //那么,u->v,w->v,w->u,这样就会让 u 多算一遍
    //如果 u 就是 1,没有影响,因为我门一开始初始化 dis[1]=0,这样回到 1 的时候再算一遍是没错的 
    //如果 u 不是 1,一定是 1 通过一系列路径,走到了 u,然后用了一次逆着走的机会,又回到了 u,对 u 计算了两遍
    //但这样的话,就不会再回到 1 了,因为不能再逆着走了
    //如果 u 通过一些路径回到 u 的话,1 能到 u,u 也能回 1,那 1 和 u 就是一个强连通分量了,不成立
    //那么既然多算了一遍 u,就不能回到 1 了,肯定也不会对答案产生影响了 
    
    //只有一个强连通分量的情况要特判 
    #define N 200006
    #define M 300006
    int fir[N],nex[M],to[M],tot;
    int fir_[N],nex_[M],to_[M],tot_;
    int dfn[N],low[N],dfscnt;
    int scc[N],scccnt,indeg[N],size[N];
    int stack[N],top;
    int n,m;
    int dis[N];
    inline void add(int u,int v){
    	to[++tot]=v;
    	nex[tot]=fir[u];fir[u]=tot;
    }
    inline void add_(int u,int v){
    	to_[++tot_]=v;
    	nex_[tot_]=fir_[u];fir_[u]=tot_;
    }
    void tarjan(int u){
    	stack[top++]=u;low[u]=dfn[u]=++dfscnt;
    	for(reg int v,i=fir[u];i;i=nex[i]){
    		v=to[i];
    		if(!dfn[v]){
    			tarjan(v);
    			low[u]=std::min(low[u],low[v]);
    		}
    		else if(!scc[v]) low[u]=std::min(low[u],dfn[v]);
    	}
    	if(dfn[u]==low[u]){
    		scccnt++;
    		do{
    			scc[stack[--top]]=scccnt;size[scccnt]++;
    		}while(stack[top]!=u);
    	}
    }
    inline void rebuild(){
    	for(reg int i=1;i<=n;i++){
    		for(reg int j=fir[i];j;j=nex[j])if(scc[i]!=scc[to[j]]){
    			add_(scc[i],scc[to[j]]);
    			add_(scc[i]+scccnt,scc[to[j]]+scccnt);
    			add_(scc[to[j]],scc[i]+scccnt);
    		}
    	}
    	for(reg int i=1;i<=scccnt;i++) size[i+scccnt]=size[i];
    }
    std::queue<int>q;
    int vis[N];
    inline void spfa(){
    	vis[scc[1]]=1;q.push(scc[1]);
    	while(!q.empty()){
    		reg int u=q.front(),v;q.pop();vis[u]=0;
    		for(reg int i=fir_[u];i;i=nex_[i]){
    			v=to_[i];
    			if(dis[v]<dis[u]+size[u]){
    				dis[v]=dis[u]+size[u];
    				if(!vis[v]) q.push(v),vis[v]=1;
    			}
    		}
    	}
    }
    int main(){
    	n=read();m=read();
    	for(reg int u,v,i=1;i<=m;i++){
    		u=read();v=read();
    		add(u,v);
    	}
    	for(reg int i=1;i<=n;i++)if(!dfn[i]) tarjan(i);
    	if(scccnt==1) return std::printf("%d",n),0;
    	rebuild();
    	spfa();
    	std::printf("%d",dis[scc[1]+scccnt]);
    //		EN;EN;
    //		for(reg int i=1;i<=n;i++) std::printf("%d ",scc[i]);EN;
    //		for(reg int i=1;i<=scccnt;i++) std::printf("%d ",size[i]);EN;
    	return 0;
    }
    
  • 相关阅读:
    Oracle11gR2下PL/SQL访问网络的错误ORA24247
    安装cx_Oracle
    搭建基于FreeNAS的共享存储
    unique constraint 和 unique index 的关系
    Oracle11gR2_RAC全静默安装攻略
    struts中的constant详解 (转载)
    网摘
    用 Google 的 FaceNet 做人脸识别极客帮课程笔记
    【Linux】Git 安装最新版
    【Jmeter】性能测试EMQ X 压测
  • 原文地址:https://www.cnblogs.com/suxxsfe/p/12738796.html
Copyright © 2011-2022 走看看