poj 3160(強連通縮點 + dp)

題目鏈接:http://poj.org/problem?id=3160


很陳舊的題目吧算是, 縮點後得到DAG, 然後就是帶點權的最長路, 唯一值得注意的是一開始的圖的點權可能是負的, 由於可以經過某個點但不取該點的權值, 所以可以把負的權值當做0來處理。。。


#include <cstdio>
#include <stack>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <set>
#include <vector>
using namespace std;

const int N = 30005;
const int M = N * 11;

struct Main {
	struct Edge {
		int v;
		Edge* next;

		void init(int a, Edge* e) {
			v = a, next = e;
		}
	};

	Edge E[M];
	Edge* head[N], * it;
	int W[N];
	int dp[N], n;

	void init(int n) {
		this->n = n;
		for (int i = 0; i < n; i++) {
			head[i] = 0, W[i] = 0, dp[i] = -1;
		}
		it = E;
	}

	void add(int u, int v) {
		it->init(v, head[u]);
		head[u] = it++;
	}

	int dfs(int u) {
		if (dp[u] != -1) return dp[u];
		int& tmp = dp[u];
		tmp = 0;

		for (Edge* e = head[u]; e; e = e->next) {
			int v = e->v;
			tmp = max(tmp, dfs(v));	
		}

		tmp += W[u];

		return tmp;
	}

	int gao() {
		int res = -1;

		for (int i = 0; i < n; i++)
			if (dp[i] == -1)
				dfs(i);

		for (int i = 0; i < n; i++) 
			res = max(res, dp[i]);

		return res;
	}

}sol;

struct SCC {

	struct Edge {
		int v;
		Edge* next;

		void init(int a, Edge* e) {
			v = a, next = e;
		}
	};

	Edge E[M], * head[N];
	int low[N], pre[N], no[N], W[N];
	int n, tot, sum, tdfn;
	stack<int> stk;

	void init(int n) {
		this->n = n;
		for (int i = 0; i < n; i++) {
			head[i] = 0;
			no[i] = -1;
			pre[i] = 0;
		}
		tot = 0, sum = 0, tdfn = 0;
	}

	void add(int u, int v) {
		E[tot].init(v, head[u]);
		head[u] = &E[tot++];
	}

	void dfs(int u) {
		pre[u] = low[u] = ++tdfn;
		stk.push(u);
		for (Edge* e = head[u]; e; e = e->next) {
			int v =	e->v;
			if (!pre[v]) {
				dfs(v);
				low[u] = min(low[u], low[v]);
			}
			else if (no[v] == -1)
				low[u] = min(low[u], pre[v]);
		}
		if (low[u] == pre[u]) {
			sum++;
			while(1) {
				int x = stk.top();
				stk.pop();
				no[x] = sum - 1;
				if (x == u) break;
			}
		}
	}

	int run() {
		for (int i = 0; i < n; i++)
			if (pre[i] == 0)
				dfs(i);

		for (int i = 0; i < n; i++)
			if (W[i] < 0) W[i] = 0;
		
		int res = 0;

		if (sum == 1) {
			for (int i = 0; i < n; i++)
				res += W[i];
		}
		else {
			sol.init(n);

			for (int i = 0; i < n; i++)
				sol.W[no[i]] += W[i];

			for (int u = 0; u < n; u++)
				for (Edge* e = head[u]; e; e = e->next) {
					int v = e->v;
					if (no[u] != no[v])
						sol.add(no[u], no[v]);
				}

			res = sol.gao();
		}

		return res;		
	
	}
}G;

int main() {
	int n, m, u, v, w;

	while (~scanf("%d%d", &n, &m)) {
		G.init(n);
		for (int i = 0; i < n; i++)
			scanf("%d", &G.W[i]);

		for (int i = 0; i < m; i++) {
			scanf("%d%d", &u, &v);
			G.add(u, v);
		}

		printf("%d\n", G.run());
	}
	return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章