zoukankan      html  css  js  c++  java
  • [USACO15JAN]草鉴定Grass Cownoisseur

    洛咕

    题意:约翰有n块草场,编号1到n,这些草场由m条单行道相连.贝西总是从1号草场出发,最后回到1号草场.她想经过尽可能多的草场,贝西在通一个草场只吃一次草,所以一个草场可以经过多次.因为草场是单行道连接,这给贝西的品鉴工作带来了很大的不便,贝西想偷偷逆向行走一次,但最多只能有一次逆行.问,贝西最多能吃到多少个草场的牧草.((n,m<=100000))

    分析:首先跑tarjan缩点,缩成一个点的强连通分量记录一下size就好,通过这个点相当于通过了size个点.

    然后对于缩点完之后的有向无环图,分别顺向建图跑spfa,求出dis1[i],表示以1(所在的强连通分量)为起点,i为终点的最长路,反向建图跑spfa,求出dis2[i],表示以1(所在的强连通分量)为终点,i为起点的最长路.

    最后枚举一下num个强连通分量u,然后枚举u可以到达的点v,(ans=max(ans,dis1[v]+dis2[u]-size[color[1]])).

    注意ans初始化为(size[color[1]]),(dis1[v])(dis2[u])要同时大于0才能更新ans(否则78分),因为(dis1[v])(dis2[u])都加了一次(size[color[1]]),所以要减掉一个.

    因为我是先反向建图再顺向建图跑的spfa,所以当我更新答案时,我的图是顺向的,所以我枚举的(u->v)逆向过来为(v->u),所以相当于我枚举的路径是(1->v->u->1),这里别思路混乱了.

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #include<map>
    #include<set>
    #define ll long long
    using namespace std;
    inline int read(){
        int x=0,o=1;char ch=getchar();
        while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
        if(ch=='-')o=-1,ch=getchar();
        while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
        return x*o;
    }
    const int N=100005;
    int n,m,ans,a[N],b[N];
    int dis1[N],dis2[N],visit[N];
    int tot,head[N],nxt[N],to[N];
    int timeclock,top,num;
    int dfn[N],low[N],st[N],color[N],size[N];
    inline void add(int a,int b){
    	nxt[++tot]=head[a];head[a]=tot;to[tot]=b;
    }
    inline void tarjan(int u){
    	dfn[u]=low[u]=++timeclock;
    	st[++top]=u;
    	for(int i=head[u];i;i=nxt[i]){
    		int v=to[i];
    		if(!dfn[v]){
    			tarjan(v);
    			low[u]=min(low[u],low[v]);
    		}
    		else if(!color[v])
    			low[u]=min(low[u],dfn[v]);
    	}
    	if(low[u]==dfn[u]){
    		color[u]=++num;
    		++size[num];
    		while(st[top]!=u){
    			color[st[top]]=num;
    			++size[num];
    			--top;
    		}
    		--top;
    	}
    }
    inline void spfa1(){
    	memset(visit,0,sizeof(visit));
    	queue<int> q1;q1.push(color[1]);
    	visit[color[1]]=1;dis1[color[1]]=size[color[1]];
    	while(q1.size()){
    		int u=q1.front();q1.pop();visit[u]=0;
    		for(int i=head[u];i;i=nxt[i]){
    			int v=to[i];
    			if(dis1[v]<dis1[u]+size[v]){
    				dis1[v]=dis1[u]+size[v];
    				if(!visit[v]){
    					q1.push(v);
    					visit[v]=1;
    				}
    			}
    		}
    	}
    }
    inline void spfa2(){
    	memset(visit,0,sizeof(visit));
    	queue<int> q2;q2.push(color[1]);
    	visit[color[1]]=1;dis2[color[1]]=size[color[1]];
    	while(q2.size()){
    		int u=q2.front();q2.pop();visit[u]=0;
    		for(int i=head[u];i;i=nxt[i]){
    			int v=to[i];
    			if(dis2[v]<dis2[u]+size[v]){
    				dis2[v]=dis2[u]+size[v];
    				if(!visit[v]){
    					q2.push(v);
    					visit[v]=1;
    				}
    			}
    		}
    	}
    }
    int main(){
    	n=read(),m=read();
    	for(int i=1;i<=m;++i){
    		a[i]=read(),b[i]=read();
    		add(a[i],b[i]);
    	}
    	for(int i=1;i<=n;++i)if(!dfn[i])tarjan(i);
    	tot=0;memset(head,0,sizeof(head));
    	for(int i=1;i<=m;++i)
    		if(color[a[i]]!=color[b[i]])add(color[b[i]],color[a[i]]);
    	spfa2();
    	tot=0;memset(head,0,sizeof(head));
    	for(int i=1;i<=m;++i)
    		if(color[a[i]]!=color[b[i]])add(color[a[i]],color[b[i]]);
    	spfa1();
    	ans=size[color[1]];
    	for(int u=1;u<=num;++u){
    		for(int i=head[u];i;i=nxt[i]){
    			int v=to[i];
    			if(dis2[u]>0&&dis1[v]>0)ans=max(ans,dis2[u]+dis1[v]-size[color[1]]);
    		}
    	}
    	printf("%d
    ",ans);
        return 0;
    }
    
    
  • 相关阅读:
    火车票起售时间
    java基础知识
    java运行
    123
    1233
    那些不能错过的XCode插件
    那些不能错过的XCode插件
    如何正确的在Android中存储特定应用文件
    如何正确的在Android中存储特定应用文件
    问题解决:listview多次调用addHeaderView和addFooterView
  • 原文地址:https://www.cnblogs.com/PPXppx/p/11381813.html
Copyright © 2011-2022 走看看