• 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();}
    
  • 相关阅读:
    css sprites图片背景优化技术
    CSS3新特性(整理贴)
    span HTML元素
    jQuery1.2选择器(2)
    JavaScript 弹出窗口总结
    jQuery1.2选择器(1)
    jquery如何判断checkbox(复选框)是否被选中
    使用 Lightbox 2 和 JavaScript 构建出色的图片库
    如何在一台电脑同时安装IE6、IE7、FF2、FF3进行网页调试
    IE的有条件注释详解(附实例代码)
  • 原文地址:https://www.cnblogs.com/yspm/p/12792522.html
Copyright © 2020-2023  润新知