天天看点

洛谷P3387 【模板】缩点 tarjan + 拓扑排序解决dp无后效性

洛谷P3387 【模板】缩点 tarjan + 拓扑排序解决dp无后效性

需要用拓扑排序解决dp的无后效性

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 10;
int head[maxn];
int dfn[maxn];
int low[maxn];
bool vis[maxn];
int colour[maxn];
int dv[maxn];
int indu[maxn];
int dist[maxn];
int tot;
int tot1;
int dex;
int cnt;
int n, m;
int ans;
struct node{
	int to;
	int next;
	int from;
	node() {}
	node(int a, int b, int c) : to(a), next(b), from(c) {}
}edge[maxn], edge1[maxn];

void edgeadd(int a, int b){
	edge[tot] = node(b, head[a], a);
	head[a] = tot++;
}

void edgeadd1(int a, int b){
	edge1[tot1] = node(b, head[a], a);
	head[a] = tot1++;
}

void init(){
	memset(head, -1, sizeof(head));
	memset(vis, 0, sizeof(vis));
	memset(dfn, 0, sizeof(dfn));
	memset(indu, 0, sizeof(indu));
	tot = 0;
	tot1 = 0;
	dex = 0;
	ans = 0;
}
stack<int> s;

void tarjan(int u){
	dfn[u] = low[u] = ++dex;
	s.push(u);
	vis[u] = 1;
	for(int i = head[u]; i != -1; i = edge[i].next){
		int v = edge[i].to;
		if(!dfn[v]){
			tarjan(v);
			low[u] = min(low[u], low[v]);
		} 
		else if(vis[v]){
			low[u] = min(low[u], dfn[v]);
		}
	}
	if(low[u] == dfn[u]){
		while(1){
			int now = s.top();
			//cout << now << endl;
			colour[now] = u;
			s.pop();
			vis[now] = 0;
			if(now == u) break;
			dv[u] += dv[now];
		}	
	}
}

int topu(){
	queue<int> q;
	for(int i = 1; i <= n; i++){
		if(colour[i] == i && !indu[i]){
			q.push(i);
			dist[i] = dv[i];		
		}	
	}
	while(!q.empty()){
			int now = q.front();
			q.pop();
			for(int i = head[now]; i != -1; i = edge1[i].next){
				int v = edge1[i].to;
				dist[v] = max(dist[v], dist[now] + dv[v]);
				indu[v]--;
				if(indu[v] == 0)
					q.push(v);
			}
		}
	int ans1 = 0;
    for (int i = 1; i <= n; i++)
    ans1 = max(ans1, dist[i]);
    return ans1;
}

int main(){
	ios::sync_with_stdio(false);
	while(cin >> n >> m){
		init();
		int x, y;
		for(int i = 1; i <= n; i++){
			cin >> dv[i];
		}
		for(int i = 1; i <= m; i++){
			cin >> x >> y;
			edgeadd(x, y);
		}
		for(int i = 1; i <= n; i++){
			if(!dfn[i])
				tarjan(i);
		}
		

		memset(head, -1, sizeof(head));
		for(int i = 0; i < m; i++){
			int o, g;
			o = colour[edge[i].from];
			g = colour[edge[i].to];
			if(o != g){
				
				edgeadd1(o, g);
				indu[g]++;
			}
		}
		cout << topu() << endl;
	}
	return 0;
} 
           

继续阅读