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

    题目

    原题链接

    解说

    (Tarjan)题的时候看到的题目,第一次见到把分层图和(Tarjan)结合的题目,觉得这样的思路很有趣,写博客以记之。

    总思路:建双层图->Tarjan缩点->最长路

    首先看到题目中“只能走一次的逆向边”这样的条件,我们会很自然地想到建一个分层图。每一个点(i)在第二层有一个对应的编号为(i+n)的对应点。第二层建边基本是第一层的还原,同时对于每一条边(x)(y)还要建一条(y)(x+n)连接一二层,由于是单向边我们就可以保证上了二层就没办法再下来,即保证了逆向边只走一次。

    图建好之后很自然地跑(Tarjan)强联通分量的板子再缩点。这时候新建的边的权值应该为目的地强联通分量的大小,这样我们只要走过这条边就可以获得去点的答案,同时因为缩点之后的图是有向无环图,可以保证一个边跑最长路时只走一次,即保证了一个点的权值只取了一次。

    最后输出答案时记得应该取(max(dis[belong[1]],dis[belong[1+n]])),因为答案可能在第一层的终点取得也可能在第二层的终点取得。

    代码

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=100000+3,maxe=100000+3;
    int head[2*maxn],tot,dfn[2*maxn],low[2*maxn],dfn_clock,scc_cnt,size[2*maxn],n,m,stk[2*maxn],top,belong[2*maxn],cnt,h[2*maxn],dis[2*maxn];
    //记得开二倍
    //话说用到的数组真多……
    bool vis[2*maxn];
    struct edge{//原边
    	int to,next;
    }e[3*maxe];//记得开三倍
    struct edge2{//缩点之后的边
    	int to,next,w;
    }ed[3*maxe];//记得开三倍
    void add(int a,int b){
    	e[++tot].to=b;
    	e[tot].next=head[a];
    	head[a]=tot;
    }
    void insert(int a,int b,int w){
    	ed[++cnt].to=b;
    	ed[cnt].w=w;
    	ed[cnt].next=h[a];
    	h[a]=cnt;
    }
    void tarjan(int u){//求强联通分量的板子
    	dfn[u]=low[u]=++dfn_clock;
    	stk[++top]=u;
    	for(int i=head[u];i;i=e[i].next){
    		int v=e[i].to;
    		if(!dfn[v]){
    			tarjan(v);
    			low[u]=min(low[u],low[v]);
    		}else if(!belong[v]) low[u]=min(low[u],dfn[v]);
    	}
    	if(low[u]==dfn[u]){
    		scc_cnt++;
    		while(1){
    			int tmp=stk[top--];
    			belong[tmp]=scc_cnt;
    			size[scc_cnt]++;
    			if(tmp==u) break;
    		}
    	}
    }
    void spfa(int s){//跑最短路
    	deque<int> q;
    	q.push_back(s);
    	while(!q.empty()){
    		int u=q.front();
    		q.pop_front();
    		vis[u]=0;
    		for(int i=h[u];i;i=ed[i].next){
    			int v=ed[i].to,w=ed[i].w;
    			if(dis[u]+w>dis[v]){
    				dis[v]=dis[u]+w;
    				if(!vis[v]){
    					vis[v]=1;
    					if(!q.empty()&&dis[v]>dis[q.front()]) q.push_front(v);
    					else q.push_back(v);
    				}
    			}
    		}
    	}
    }
    int main(){
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=m;i++){
    		int x,y;
    		scanf("%d%d",&x,&y);
    		add(x,y);
    		add(x+n,y+n);
    		add(y,x+n);//分层图核心加边
    	}
    	for(int i=1;i<=2*n;i++) if(!dfn[i]) tarjan(i);
    	for(int i=1;i<=2*n;i++){//缩点
    		for(int j=head[i];j;j=e[j].next){
    			int x=belong[i],y=belong[e[j].to];
    			if(x!=y) insert(x,y,size[y]);
    		}
    	}
    	spfa(belong[1]);
    	printf("%d
    ",max(dis[belong[1]],dis[belong[1+n]]));
    	return 0;
    }
    

    幸甚至哉,歌以咏志。

  • 相关阅读:
    剑指Offer--复杂链表的复制
    剑指offer--第43题 1~n整数中1出现的次数
    剑指Offer--第50题 第一次只出现一次的字符
    剑指offer--扑克牌顺子
    MySQL免安装使用教程
    TortoiseGit的使用参考
    剑指Offer-- 第58题 翻转字符串
    剑指Offer-- 第45题 把数组排成最小数
    剑指Offer-- 第49题 丑数
    SpringBoot-data-jpa的简单使用
  • 原文地址:https://www.cnblogs.com/DarthVictor/p/13391347.html
Copyright © 2011-2022 走看看