zoukankan      html  css  js  c++  java
  • 缩点 洛谷P3387

    Description

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


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


    Input

    第一行,n,m。第二行,n个整数,依次代表点权。第三至m+2行,每行两个整数u,v,表示u->v有一条有向边。


    Output

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


    Hint

    n<=104,m<=105,点权<=1000。


    Solution

    tarjan缩点+DAG图上的dp。

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<stack>
    #include<queue>
    #define maxn 200005
    #define inf 0x3f3f3f3f
    using namespace std;
    struct Edge{
    	int u;
    	int v;
    	int next;
    }edge[maxn],edge2[maxn];
    stack<int>stk;
    int first[maxn],last[maxn],dfn[maxn],low[maxn],belong[maxn],rd[maxn],sum[maxn],w[maxn],first2[maxn],last2[maxn],dp[maxn];
    int node,dfn_TimeClock,cnt,node2,n,m,x,y,ans;
    bool vis[maxn];
    void addedge(int u,int v){
    	edge[++node]=(Edge){u,v,0};
    	if(first[u]==0)first[u]=node;
    	else edge[last[u]].next=node;
    	last[u]=node;
    }
    void addedge2(int u,int v){
    	edge2[++node2]=(Edge){u,v,0};
    	if(first2[u]==0)first2[u]=node2;
    	else edge2[last2[u]].next=node2;
    	last2[u]=node2;
    }
    void init(){
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=n;i++){
    		scanf("%d",&w[i]);
    	}
    	for(int i=1;i<=m;i++){
    		scanf("%d%d",&x,&y);
    		addedge(x,y);
    	}
    }
    void tarjan(int s){
    	dfn[s]=low[s]=++dfn_TimeClock;
    	stk.push(s);
    	for(int i=first[s];i;i=edge[i].next){
    		int j=edge[i].v;
    		if(!dfn[j]){
    			tarjan(j);
    			low[s]=min(low[s],low[j]);
    		}
    		else if(!belong[j]){
    			low[s]=min(low[s],dfn[j]);
    		}
    	}
    	if(low[s]==dfn[s]){
    		cnt++;
    		belong[s]=cnt;
    		sum[cnt]+=w[s];
    		while(stk.top()!=s){
    			belong[stk.top()]=cnt;
    			sum[cnt]+=w[stk.top()];
    			stk.pop();
    		}
    		stk.pop();
    	}
    }
    void Set_New(){
    	for(int i=1;i<=n;i++){
    		if(!dfn[i])tarjan(i);
    	}
    	for(int i=1;i<=n;i++){
    		for(int p=first[i];p;p=edge[p].next){
    			int j=edge[p].v;
    			if(belong[i]!=belong[j]){
    				addedge2(belong[i],belong[j]);
    				rd[belong[j]]++;
    			}
    		}
    	}
    }
    void topo(){
    	queue<int>q;
    	for(int i=1;i<=cnt;i++){
    		if(rd[i]==0){
    			q.push(i);
    			dp[i]=sum[i];
    		}
    	}
    	while(!q.empty()){
    		int t=q.front();
    		q.pop();
    		for(int i=first2[t];i;i=edge2[i].next){
    			int j=edge2[i].v;
    			dp[j]=max(dp[j],dp[t]+sum[j]);
    			rd[j]--;
    			if(rd[j]==0)q.push(j);
    		}
    	}
    }
    int main(){
    	init();
    	Set_New();
    	topo();
    	for(int i=1;i<=cnt;i++){
    		ans=max(ans,dp[i]);
    	}
    	printf("%d
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    GO语言面向对象06---面向对象练习01
    GO语言面向对象05---接口的多态
    GO语言面向对象04---接口的继承
    GO语言面向对象03---接口与断言
    GO语言面向对象02---继承
    Go语言练习---判断闰年以及根据现在的秒数求现在的年月日
    [操作系统] 线程管理
    [操作系统] 进程的状态
    [操作系统] 进程控制块
    关于这次计算机设计大赛
  • 原文地址:https://www.cnblogs.com/virtual-north-Illya/p/10045408.html
Copyright © 2011-2022 走看看