zoukankan      html  css  js  c++  java
  • 洛谷 P3387 【模板】缩点

    洛谷 P3387 【模板】缩点

    洛谷传送门

    题目背景

    缩点+DP

    题目描述

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

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

    输入格式

    第一行两个正整数 n,mn,m

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

    第三至 m+2m+2 行,每行两个整数 u,vu,v,表示一条 u ightarrow vuv 的有向边。

    输出格式

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


    题解:

    缩点之后就变成DAG了,就可以拓扑DP了。

    代码:

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<queue>
    using namespace std;
    const int maxn=1e4+4;
    const int maxm=1e5+5;
    int n,m;
    int a[maxn];
    int tot,head[maxn],nxt[maxm],to[maxm],from[maxm];
    int dfn[maxn],low[maxn];
    int st[maxn],top,cnt;
    bool v[maxn];
    int id[maxn],rudu[maxn],dp[maxn];
    int tot1,head1[maxn],nxt1[maxm],to1[maxm];
    void add(int x,int y)
    {
    	to[++tot]=y;
    	nxt[tot]=head[x];
    	from[tot]=x;
    	head[x]=tot;
    }
    void add1(int x,int y)
    {
    	to1[++tot1]=y;
    	nxt1[tot1]=head1[x];
    	head1[x]=tot1;
    }
    void tarjan(int x)
    {
    	dfn[x]=low[x]=++cnt;
    	st[++top]=x;
    	v[x]=1;
    	for(int i=head[x];i;i=nxt[i])
    	{
    		int y=to[i];
    		if(!dfn[y])
    		{
    			tarjan(y);
    			low[x]=min(low[x],low[y]);
    		}
    		else if(v[y])
    			low[x]=min(low[x],dfn[y]);
    	}
    	if(dfn[x]==low[x])
    	{
    		int now;
    		do
    		{
    			now=st[top--];
    			id[now]=x;
    			v[now]=0;
    			a[x]+=a[now];
    		}while(now!=x);
    	}
    }
    queue<int> q;
    int topsort()
    {
    	for(int i=1;i<=n;i++)
    		if((id[i]==i)&&(!rudu[i]))
    		{
    			q.push(i);
    			dp[i]=a[i];
    		}
    	while(!q.empty())
    	{
    		int x=q.front();
    		q.pop();
    		for(int i=head1[x];i;i=nxt1[i])
    		{
    			int y=to1[i];
    			dp[y]=max(dp[y],dp[x]+a[y]);
    			rudu[y]--;
    			if(!rudu[y])
    				q.push(y);
    		}
    	}
    	int ans=0;
    	for(int i=1;i<=n;i++)
    		ans=max(ans,dp[id[i]]);
    	return ans;
    }
    int main()
    {
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=n;i++)
    		scanf("%d",&a[i]);
    	for(int i=1;i<=m;i++)
    	{
    		int x,y;
    		scanf("%d%d",&x,&y);
    		add(x,y);
    	}
    	for(int i=1;i<=n;i++)
    		if(!dfn[i])
    			tarjan(i);
    	for(int i=1;i<=m;i++)
    	{
    		int x=from[i],y=to[i];
    		if(id[x]!=id[y])
    		{
    			add1(id[x],id[y]);
    			rudu[id[y]]++;
    		}
    	}
    	printf("%d
    ",topsort());
    	return 0;
    }
    
  • 相关阅读:
    [贪心]P1049 装箱问题
    js中字符串转换为日期和比较大小
    weblogic配置数据源出错
    myeclipse安装svn插件的多种方式
    使用令牌实现防重复提交
    struts1.3异常处理机制
    spring log4j.properties
    spring jdbc.property的配置与使用
    js循环array,json,map
    java web的一些特殊用法(一)
  • 原文地址:https://www.cnblogs.com/fusiwei/p/14081249.html
Copyright © 2011-2022 走看看