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;
    }
    
    
  • 相关阅读:
    算法训练 表达式计算
    基础练习 十六进制转十进制
    基础练习 十六进制转十进制
    基础练习 十六进制转十进制
    New ways to verify that Multipath TCP works through your network
    TCP的拥塞控制 (Tahoe Reno NewReno SACK)
    Multipath TCP Port for Android 4.1.2
    How to enable ping response in windows 7?
    NS3
    Multipath TCP Port for Android
  • 原文地址:https://www.cnblogs.com/PPXppx/p/11381813.html
Copyright © 2011-2022 走看看