• [洛谷P3387]【模板】缩点


    题目大意:给定一个$n$个点$m$条边有向图,第$i$个点有权值$w_i$,求一条路径,使路径经过的点权值之和最大,输出点权和,(多次经过一个点只算一次点权)

    题解:$tarjan$缩点+$DP$

    卡点:1.多处$i,j$打错

    2.要求找到一条路径,看成了终点必须为$n$


    C++ Code:

    #include <cstdio>
    #define maxn 10010
    #define maxm 100010
    struct Graph {
    	int head[maxn], cnt;
    	struct Edge {
    		int to, nxt;
    	} e[maxm << 1];
    	void add(int a, int b) {
    		e[++cnt] = (Edge) {b, head[a]}; head[a] = cnt;
    	}
    } G1, G2;
    int n, m, ans;
    int ind[maxn], q[maxn], h, t;
    int f[maxn], w[maxn], dp[maxn];
    int DFN[maxn], low[maxn], idx, res[maxn], cnt;
    int S[maxn], top;
    bool ins[maxn];
    inline int min(int a, int b) {return a < b ? a : b;}
    inline int max(int a, int b) {return a > b ? a : b;}
    void tarjan(int rt) {
    	DFN[rt] = low[rt] = ++idx;
    	ins[S[++top] = rt] = true;
    	int v;
    	for (int i = G1.head[rt]; i; i = G1.e[i].nxt) {
    		v = G1.e[i].to;
    		if (!DFN[v]) {
    			tarjan(v);
    			low[rt] = min(low[rt], low[v]);
    		} else if (ins[v]) low[rt] = min(low[rt], DFN[v]);
    	}
    	if (DFN[rt] == low[rt]) {
    		cnt++;
    		do {
    			ins[v = S[top--]] = false;
    			res[v] = cnt;
    			f[cnt] += w[v];
    		} while (v != rt);
    	}
    }
    int main() {
    	scanf("%d%d", &n, &m);
    	for (int i = 1; i <= n; i++) scanf("%d", w + i);
    	for (int i = 0; i < m; i++) {
    		int a, b;
    		scanf("%d%d", &a, &b);
    		G1.add(a, b);
    	}
    	for (int i = 1; i <= n; i++) {
    		if (!DFN[i]) tarjan(i);
    	}
    	for (int i = 1; i <= n; i++) {
    		for (int j = G1.head[i]; j; j = G1.e[j].nxt) {
    			int v = G1.e[j].to;
    			if (res[i] != res[v]) G2.add(res[i], res[v]), ind[res[v]]++;
    		}
    	}
    	for (int i = 1; i <= cnt; i++) {
    		if (!ind[i]) q[t++] = i, dp[i] = f[i], ans = max(ans, dp[i]);
    	}
    	t--;
    	while (h <= t) {
    		int u = q[h++];
    		for (int i = G2.head[u]; i; i = G2.e[i].nxt) {
    			int v = G2.e[i].to;
    			dp[v] = max(dp[v], dp[u] + f[v]);
    			if (!--ind[v]) q[++t] = v, ans = max(ans, dp[v]);
    		}
    	}
    	printf("%d
    ", ans);
    	return 0;
    } 
    
  • 相关阅读:
    sublime使用
    eclipse导入工程中文乱码
    npm 代理
    栈和堆
    Linux常用命令大全
    Google云开启SSH登录方法
    景安快运挂在磁盘-支持宝塔
    discuz 批量删除回复并且保留主题的方法,亲测3.4版本通过
    博客园去掉页面的广告的方法
    WordPress忘记后台登录地址时怎么办?万能登录地址
  • 原文地址:https://www.cnblogs.com/Memory-of-winter/p/9603943.html
Copyright © 2020-2023  润新知