zoukankan      html  css  js  c++  java
  • P3387 【模板】缩点 [强连通分量][DAG]

    题意

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

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

    Solution

    先缩点,就成了一个DAG图,做一遍拓扑排序,按拓扑序进行DP。

    代码

    #include<bits/stdc++.h>
    using namespace std;
    const int N = 10010,M = 100010 * 2;
    int head[N],ver[M],nxt[M],hc[N],vc[M],nc[M],tot,tc;
    int ins[N],low[N],s[N],dfn[N],c[N],cnt,num,top,sum[N];
    vector<int> scc[N];
    
    void add(int x,int y){
    	nxt[++tot] = head[x];
    	ver[tot] = y;
    	head[x] = tot;
    }
    void addc(int x,int y){
    	nc[++tc] = hc[x];
    	vc[tc] = y;
    	hc[x] = tc;
    }
    void tarjan(int x){
    	low[x] = dfn[x] = ++num;
    	s[++top] = x; ins[x] = 1;
    	for(int i = head[x]; i; i = nxt[i]){
    		int v = ver[i];
    		if(!dfn[v]){
    			tarjan(v);
    			low[x] = min(low[x],low[v]);
    		}
    		else if(ins[v])
    			low[x] = min(low[x],dfn[v]);
    	}
    	if(low[x] == dfn[x]){
    		cnt++; int y;
    		do{
    			y = s[top--]; ins[y] = 0;
    			scc[cnt].push_back(y);
    			c[y] = cnt;
    		}while(x != y);
    	}
    }
    int n,m,a[N],deg[N],dp[N];
    void dfs(int x){
    	dp[x] = sum[x];
    	for(int i = hc[x]; i; i = nc[i]){
    		int v = vc[i];
    		dfs(v);
    		dp[x] = max(dp[x],dp[v] + sum[x]);
    	}
    } 
    int topo(){
    	queue<int> q;
    	for(int i = 1; i <= cnt; i++)
    		if(!deg[i]) {
    			q.push(i);
    			dp[i] = sum[i];
    		}
    	while(!q.empty()){
    		int x = q.front(); q.pop();
    		for(int i = hc[x]; i; i = nc[i]){
    			int y = vc[i];
    			dp[y] = max(dp[y],dp[x] + sum[y]);
    			deg[y]--;
    			if(!deg[y]) 
    				q.push(y);
    		}
    	}
    	int ans = 0;
    	for(int i = 1; i <= cnt; i++)
    		ans = max(ans,dp[i]);
    	return ans;
    }
    
    int main(){
    	cin >> n >> m;
    	for(int i = 1; i <= n; i++)
    		cin >> a[i];
    	for(int i = 1; i <= m; i++){
    		int u,v;
    		cin >> u >> v;
    		add(u,v);
    	}
    	for(int i = 1; i <= n; i++)
    		if(!dfn[i]) tarjan(i);
    	for(int x = 1; x <= n; x++){
    		for(int i = head[x]; i; i = nxt[i]){
    			int v = ver[i];
    			if(c[x] == c[v]) continue;
    			addc(c[x],c[v]);
    			deg[c[v]]++;
    		}
    	}
    	for(int i = 1; i <= cnt; i++){
    		for(int j = 0; j < scc[i].size(); j++)
    			sum[i] += a[scc[i][j]];
    	}
    	cout << topo() << endl;
    	return 0;
    }
    
  • 相关阅读:
    SQL Server 2005 之事务日志体系 (一)
    SQL Server 2005 事务日志之逻辑结构(二)
    SQL Server 2005 清除备份 还原历史记录
    SQL Server 验证器
    SQL Server 2005 事务日志之物理体系(三)
    程序设计语言原理重要概念
    Java作业四 图形用户界面程序设计和多线程
    Java作业二 面向对象程序设计
    Java作业三 语言基础与面向对象
    Java课程学习总结
  • 原文地址:https://www.cnblogs.com/FoxC/p/12219424.html
Copyright © 2011-2022 走看看