zoukankan      html  css  js  c++  java
  • Tarjan+topsort(DP)【P3387】 [模板]缩点

    Description

    给定一个n个点m条边有向图,每个点有一个权值,求一条路径,使路径经过的点权值之和最大。你只需要求出这个权值和。

    允许多次经过一条边或者一个点,但是,重复经过的点,权值只计算一次。

    Input

    第一行,n,m

    第二行,n个整数,依次代表点权

    第三至m+2行,每行两个整数u,v,表示u->v有一条有向边

    Output

    共一行,最大的点权之和。

    缩点+DP这是题目说的

    先缩点,对于每一个联通块之间建边,这时得到一张(DAG)(有向无环图)

    我们对其跑拓扑排序,然后开一个数组(dis)记录到达某个点的最大值.

    对于那些入度为0的点,我们初始化其(dis)为其联通块的点权之和.

    然后每次取(max)即可.

    最终(ans)即为对到达每个点的(dis)(max)

    代码

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #define R register
    
    using namespace std;
    
    const int gz=50008;
    
    inline void in(int &x)
    {
    	int f=1;x=0;char s=getchar();
    	while(!isdigit(s)){if(s=='-')f=-1;s=getchar();}
    	while(isdigit(s)){x=x*10+s-'0';s=getchar();}
    	x*=f;
    }
    
    int head[gz],tot,val[gz],v[gz],h[gz],dis[gz],ins[gz],ans,n,m;
    
    struct cod{int u,v;}edge[gz<<1],e[gz<<1];
    
    inline void add(R int x,R int y)
    {
    	edge[++tot].u=head[x];
    	edge[tot].v=y;
    	head[x]=tot;
    }
    
    inline void ado(R int x,R int y)
    {
    	e[++tot].u=h[x];
    	e[tot].v=y;
    	h[x]=tot;
    }
    
    int dfn[gz],belong[gz],idx,low[gz],stk[gz],top,col;
    
    bool inq[gz];
    
    void tarjan(R int x)
    {
    	low[x]=dfn[x]=++idx;
    	stk[++top]=x;inq[x]=true;
    	for(R int i=head[x];i;i=edge[i].u)
    	{
    		if(!dfn[edge[i].v])
    		{
    			tarjan(edge[i].v);
    			low[x]=min(low[x],low[edge[i].v]);
    		}
    		else if(inq[edge[i].v])
    			low[x]=min(low[x],dfn[edge[i].v]);
    	}
    	if(low[x]==dfn[x])
    	{
    		int now=-1;
    		col++;
    		while(now!=x)
    		{
    			now=stk[top--];
    			belong[now]=col;
    			inq[now]=false;
    			v[col]+=val[now];
    		}
    	}
    }
    
    inline void topsort()
    {
    	top=0;
    	for(R int i=1;i<=col;i++)
    		if(!ins[i])stk[++top]=i,dis[i]=v[i];
    	while(top)
    	{
    		int u=stk[top--];
    		for(R int i=h[u];i;i=e[i].u)
    		{
    			ins[e[i].v]--;
    			dis[e[i].v]=max(dis[e[i].v],dis[u]+v[e[i].v]);
    			if(!ins[e[i].v])stk[++top]=e[i].v;
    		}
    	}
    	for(R int i=1;i<=col;i++)
    		ans=max(ans,dis[i]);
    	printf("%d
    ",ans);
    }
    
    int main()
    {
    	in(n),in(m);
    	for(R int i=1;i<=n;i++)in(val[i]);
    	for(R int i=1,x,y;i<=m;i++)
    	{
    		in(x),in(y);
    		add(x,y);
    	}
    	for(R int i=1;i<=n;i++)
    		if(!dfn[i])tarjan(i);
    	tot=0;
    	for(R int i=1;i<=n;i++)
    		for(R int j=head[i];j;j=edge[j].u)
    			if(belong[i]!=belong[edge[j].v])
    			{
    				ins[belong[edge[j].v]]++;
    				ado(belong[i],belong[edge[j].v]);
    			}
    	topsort();
    }
    
  • 相关阅读:
    matlab mex中C++内存全局共享和持久化
    算法导论01---到底何为算法(由算法联想到的大学教育)
    在Visual Studio项目中根据系统平台自动引用32或64位的DLL
    POJ2352【树状数组】
    artDialog双击会关闭对话框的修改
    利用AWR 查看SQL 执行计划
    Sql获取数据集中各类型中的最大值(最新值)
    容器常用操作
    运行容器的最佳实践
    两种进入容器的方法
  • 原文地址:https://www.cnblogs.com/-guz/p/9899509.html
Copyright © 2011-2022 走看看