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

    Description

    link

    给定一个有向图,从 (1) 号出发,最后要求回到 (1)

    其中允许经过重复的点,同时允许走一次反向边

    求最多经过多少个点

    (n,m le 10^5)

    Solution

    这种题上了缩点没的说(不会缩点?左转 (Luogu) 模板区)

    (下文的图都是指缩完点的图)

    然后我们发现在这个 (DAG) 上面跑最长路 (dp) 并不可行,反悔并不好处理

    分层呀!

    图上的所有边我们可以建成这样:

    第一层的边复制到第二层,然后在第一层的终点向第二层的起点建边

    再跑最长路

    (本题的唯一思考点……)

    正确性?如果重复经过点呢?

    请思考我们这个最长路会在哪些点上

    如果往出边走,是不会回到 (1) 的(要不就又是环了)

    只会是往前走一次,再回到 (1)

    所以正确性是有保证的

    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    namespace yspm{
    	inline int read()
    	{
    		int res=0,f=1; char k;
    		while(!isdigit(k=getchar())) if(k=='-') f=-1;
    		while(isdigit(k)) res=res*10+k-'0',k=getchar();
    		return res*f;
    	}
    	const int N=2e5+10;
    	int st[N],top;
    	vector<int> g[N],vec[N];
    	int dfn[N],low[N],tim,vis[N],val[N],tot,id[N],res[N],n,m;
    	inline void tarjan(int x)
    	{
    		dfn[x]=low[x]=++tim; vis[x]=1; st[++top]=x;
    		int siz=g[x].size(); 
    		for(int i=0;i<siz;++i)
    		{
    			int t=g[x][i]; 
    			if(!dfn[t]) tarjan(t),low[x]=min(low[t],low[x]);
    			else if(vis[t]) low[x]=min(low[x],dfn[t]);
    		}
    		if(dfn[x]==low[x])
    		{
    			++tot; 
    			do{
    				int t=st[top]; val[tot]++;
    				id[t]=tot;
    				vis[t]=0; top--;
    			}while(st[top+1]!=x);
    		}
    		return ;
    	}
    	inline void spfa(int s)
    	{
    		memset(vis,0,sizeof(vis));
    		queue<int>q; q.push(s); vis[s]=1;
    		while(!q.empty())
    		{
    			int fr=q.front(); vis[fr]=0; q.pop();
    			int siz=vec[fr].size();
    			for(int i=0;i<siz;++i)
    			{
    				int t=vec[fr][i]; 
    				if(res[t]<res[fr]+val[fr]) 
    				{
    					res[t]=res[fr]+val[fr];
    					if(!vis[t]) vis[t]=1,q.push(t);
    				}
    			}
    		} return ;
    	}
    	signed main()
    	{
    		n=read(); m=read();
    		for(int i=1;i<=m;++i)
    		{
    			int x=read(),y=read();
    			g[x].push_back(y);
    		}
    		for(int i=1;i<=n;++i) if(!dfn[i]) tarjan(i);
    		for(int i=1;i<=tot;++i) val[i+tot]=val[i];
    		for(int i=1;i<=n;++i)
    		{
    			int sz=g[i].size();
    			for(int j=0;j<sz;++j)
    			{
    				if(id[g[i][j]]!=id[i]) 
    				{
    					vec[id[i]].push_back(id[g[i][j]]);
    					vec[id[i]+tot].push_back(id[g[i][j]]+tot);
    					vec[id[g[i][j]]].push_back(id[i]+tot);
    				}
    			}
    		}
    		spfa(id[1]);
    		printf("%lld
    ",res[id[1]+tot]);
    		return 0;
    	}
    }
    signed main(){return yspm::main();}
    
  • 相关阅读:
    LeetCode 769. Max Chunks To Make Sorted
    LeetCode 845. Longest Mountain in Array
    LeetCode 1059. All Paths from Source Lead to Destination
    1129. Shortest Path with Alternating Colors
    LeetCode 785. Is Graph Bipartite?
    LeetCode 802. Find Eventual Safe States
    LeetCode 1043. Partition Array for Maximum Sum
    LeetCode 841. Keys and Rooms
    LeetCode 1061. Lexicographically Smallest Equivalent String
    LeetCode 1102. Path With Maximum Minimum Value
  • 原文地址:https://www.cnblogs.com/yspm/p/12792522.html
Copyright © 2011-2022 走看看