zoukankan      html  css  js  c++  java
  • 洛谷—P3387 【模板】缩点

    题目背景

    缩点+DP

    题目描述

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

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

    输入输出格式

    输入格式:
    第一行,n,m

    第二行,n个整数,依次代表点权

    第三至m+2行,每行两个整数u,v,表示u->v有一条有向边

    输出格式:

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

    输入输出样例

    输入样例#1:
    2 2
    1 1
    1 2
    2 1
    输出样例#1:
    2
    说明 n<=10^4 ,m <=10^5 ,点权 <= 1000
    算法:Tarjan缩点+DAGdp

    思路 : 题目的思路很清晰,都有提示,但是我第一次写的时候 WA了一组 ,T了一组
    在这里插入图片描述
    代码如下 :

    #include <queue>
    #include <stack>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    const int maxn = 1e4 + 50;
    const int maxm = 1e5 + 50;
    
    struct edge {
        int nxt ,to ;
    }ss[maxm * 10 ];
    
    stack<int>sta ;
    int head[maxn] ,dfn[maxn] ,low[maxn] ,w[maxn] ;
    int cnt ,Index ,scc ,n ,m ,flag[maxn] ;
    int sum[maxn] ,in[maxn] ,dp[maxn] ;
    bool vis[maxn] ;
    
    void init() {
        memset(head ,-1 ,sizeof(head));
        memset(vis ,false ,sizeof(vis));
    }
    
    inline int Min(int a,int b) { return a > b ? b : a ; }
    inline int Max(int a,int b) { return a > b ? a : b ; }
    
    void add_edge (int u ,int v ){
        ss[++cnt].to = v;
        ss[cnt].nxt = head[u] ;
        head[u] = cnt ;
    }
    
    void tarjan(int x) {
        dfn[x] = low[x] = ++Index ;
        vis[x] = true ; sta.push(x) ;
        for (int i = head[x] ; ~i ; i = ss[i].nxt ) {
            if ( !dfn[ss[i].to] ) {
                tarjan(ss[i].to);
                low[x] = Min(low[x] ,low[ss[i].to]) ;
            } else if ( vis[ss[i].to] ) {
                low[x] = Min(low[x] ,dfn[ss[i].to]) ;
            }
        }
        if ( low[x] == dfn[x] ) {
            scc ++;
            int v;
            do {
                v = sta.top() ; sta.pop();
                flag[v] = scc ;
            } while ( x != v ) ;
        }
    }
    
    void toposort() {
        queue<int >que ;
        for (int i = 1 ; i <= scc ; i ++ ) {
            if( !in[i] ) {
                que.push(i);
                dp[i] = sum[i] ;
            }
        }
    //	for (int i = 1 ; i <= scc ; i ++ ) {
    //		if ( !in[i] ) {
    //			printf("%d %d
    ",i ,sum[i]) ;
    //		}
    //	} puts("") ;
        while ( !que.empty() ) {
            int top = que.front() ;que.pop();
            for (int i = 1 ; i <= n ; i ++ ) {
                if ( flag[i] == top ) {
                    for (int j = head[i] ; ~j ; j = ss[j].nxt ) {
                        if ( flag[i] != flag[ss[j].to] ) {
                            que.push(flag[ss[j].to]) ;
                            dp[flag[ss[j].to]] = Max(dp[flag[ss[j].to]] ,dp[flag[i]] + sum[flag[ss[j].to]]) ;
                        }
                    }
                }
            }
        } 
    }
    
    int main() {
        //FILE *fp;
        //fp = fopen("in.txt" ,"r") ;
        init() ; int u ,v ; 
        //fscanf(fp, "%d %d" ,&n ,&m ) ;
        scanf("%d %d",&n ,&m ) ;
        for (int i = 1 ; i <= n ; i ++ ) {
            //fscanf(fp ,"%d" ,&w[i] );
            scanf("%d",&w[i]);
        }
        for (int i = 1 ; i <= m ; i ++ ) {
            //fscanf(fp ,"%d %d",&u ,&v ) ;
            scanf("%d %d" ,&u ,&v ) ;
            add_edge(u ,v ) ;
        }
        for (int i = 1 ; i <= n ; i ++ ) {
            if ( !vis[i] ) {
                tarjan(i);
            }
        }
        for (int i = 1 ; i <= n ; i ++ ) {
            if ( !flag[i] ) flag[i] = ++ scc ;
        }
    //	for (int i = 1 ; i <= n ; i ++ ) {
    //		printf("%d ",flag[i]) ;
    //	} puts("");
        for (int i = 1 ; i <= n ; i ++ ) {
            for (int j = head[i] ; ~j ; j = ss[j].nxt ) {
                if ( flag[i] != flag[ss[j].to] ) {
                    in[flag[ss[j].to]] ++;
                }
            }
        }
        for (int i = 1 ; i <= n ; i ++ ) {
            sum[flag[i]] += w[i];
        } 
    //	for (int i = 1 ; i <= scc ; i ++ ) {
    //		printf("%d ",sum[i]) ;
    //	} puts("");
        toposort() ;
        int maxx = -0x3f3f3f3f ;
        for (int i = 1 ; i <= scc ; i ++ ) {
            //printf("%d ",dp[i]);
            maxx = Max(maxx ,dp[i] ) ;
        } //puts("");
        printf("%d
    ",maxx) ;
        //fclose(fp) ;
        return 0;
    }
    

    后来想了想,我的那个入度还能够利用一下,因此改了一下
    在这里插入图片描述

    #include <queue>
    #include <stack>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    const int maxn = 1e4 + 50;
    const int maxm = 1e5 + 50;
    
    struct edge {
        int nxt ,to ;
    }ss[maxm * 10 ];
    
    stack<int>sta ;
    int head[maxn] ,dfn[maxn] ,low[maxn] ,w[maxn] ;
    int cnt ,Index ,scc ,n ,m ,flag[maxn] ;
    int sum[maxn] ,in[maxn] ,dp[maxn] ;
    bool vis[maxn] ;
    
    void init() {
        memset(head ,-1 ,sizeof(head));
        memset(vis ,false ,sizeof(vis));
    }
    
    inline int Min(int a,int b) { return a > b ? b : a ; }
    inline int Max(int a,int b) { return a > b ? a : b ; }
    
    void add_edge (int u ,int v ){
        ss[++cnt].to = v;
        ss[cnt].nxt = head[u] ;
        head[u] = cnt ;
    }
    
    void tarjan(int x) {
        dfn[x] = low[x] = ++Index ;
        vis[x] = true ; sta.push(x) ;
        for (int i = head[x] ; ~i ; i = ss[i].nxt ) {
            if ( !dfn[ss[i].to] ) {
                tarjan(ss[i].to);
                low[x] = Min(low[x] ,low[ss[i].to]) ;
            } else if ( vis[ss[i].to] ) {
                low[x] = Min(low[x] ,dfn[ss[i].to]) ;
            }
        }
        if ( low[x] == dfn[x] ) {
            scc ++;
            int v;
            do {
                v = sta.top() ; sta.pop();
                flag[v] = scc ;
            } while ( x != v ) ;
        }
    }
    
    void toposort() {
        queue<int >que ;
        for (int i = 1 ; i <= scc ; i ++ ) {
            if( !in[i] ) {
                que.push(i);
                dp[i] = sum[i] ;
            }
        }
        while ( !que.empty() ) {
            int top = que.front() ; que.pop();
            for (int i = 1 ; i <= n ; i ++ ) {
                if ( flag[i] == top ) {
                    for (int j = head[i] ; ~j ; j = ss[j].nxt ) {
                        if ( flag[i] != flag[ss[j].to] ) {
                            in[flag[ss[j].to]] -- ;///这一句
                            if ( !in[flag[ss[j].to]] )///这一句
                                que.push(flag[ss[j].to]) ;///这一句
                            dp[flag[ss[j].to]] = Max(dp[flag[ss[j].to]] ,dp[flag[i]] + sum[flag[ss[j].to]]) ;
                        }
                    }
                }
            }
        } 
    }
    
    int main() {
    //	FILE *fp;
    //	fp = fopen("in.txt" ,"r") ;
        init() ; int u ,v ; 
        //fscanf(fp, "%d %d" ,&n ,&m ) ;
        scanf("%d %d",&n ,&m ) ;
        for (int i = 1 ; i <= n ; i ++ ) {
            //fscanf(fp ,"%d" ,&w[i] );
            scanf("%d",&w[i]);
        }
        for (int i = 1 ; i <= m ; i ++ ) {
            //fscanf(fp ,"%d %d",&u ,&v ) ;
            scanf("%d %d" ,&u ,&v ) ;
            add_edge(u ,v ) ;
        }
        for (int i = 1 ; i <= n ; i ++ ) {
            if ( !vis[i] ) {
                tarjan(i);
            }
        }
        for (int i = 1 ; i <= n ; i ++ ) {
            if ( !flag[i] ) flag[i] = ++ scc ;
        }
    //	for (int i = 1 ; i <= n ; i ++ ) {
    //		printf("%d ",flag[i]) ;
    //	} puts("");
        for (int i = 1 ; i <= n ; i ++ ) {
            for (int j = head[i] ; ~j ; j = ss[j].nxt ) {
                if ( flag[i] != flag[ss[j].to] ) {
                    in[flag[ss[j].to]] ++;
                }
            }
        }
        for (int i = 1 ; i <= n ; i ++ ) {
            sum[flag[i]] += w[i];
        } 
    //	for (int i = 1 ; i <= scc ; i ++ ) {
    //		printf("%d ",sum[i]) ;
    //	} puts("");
        toposort() ;
        int maxx = -0x3f3f3f3f ;
        for (int i = 1 ; i <= scc ; i ++ ) {
            //printf("%d ",dp[i]);
            maxx = Max(maxx ,dp[i] ) ;
        } //puts("");
        printf("%d
    ",maxx) ;
        return 0;
    }
    

    然后就卡在里这里,后面不知道了怎么改,在网上找了一个答案,发现跟我的思路差不多,但是我的就是不对,后来通过这两组数据的缩点对比我发现我的tarjan写错了,最后也没有想到解决方法,就万恶的改了一下自己缩点的模板,最后代码是这样的

    #include <bits/stdc++.h>
    
    using namespace std;
    
    const int maxn = 1e4 + 50 ;
    
    struct edge {
    	int nxt ,u ,v ;
    }ss[maxn * 10] ,s[maxn * 10];
    
    int head[maxn] ,dfn[maxn] ,low[maxn] ,pos ;
    int n ,m ,cnt ,Index ,h[maxn] ,sta[maxn];
    int flag[maxn] ,sum[maxn] ,cnt1 ,in[maxn] ,dp[maxn] ;
    bool vis[maxn] ;
    
    inline int Min(int a,int b) { return a > b ? b : a ; }
    inline int Max(int a,int b) { return a > b ? a : b ; }
    
    void init(){
    	cnt1 = pos = cnt = Index = 0;
    	memset(vis ,false ,sizeof(vis)) ;
    	memset(head ,-1 ,sizeof(head)) ;
    	memset(h ,-1 ,sizeof(h)) ;
    }
    
    void add_edge(int u,int v) {
    	ss[++cnt].u = u ;
    	ss[cnt].v = v;
    	ss[cnt].nxt = head[u] ;
    	head[u] = cnt ;
    }
    
    void tarjan(int x) {
    	dfn[x] = low[x] = ++Index ;
    	vis[x] = true ; sta[++pos] = x;
    	for (int i = head[x] ; ~i ; i = ss[i].nxt ) {
    		if ( !dfn[ss[i].v] ) {
    			tarjan(ss[i].v) ;
    			low[x] = Min(low[x] ,low[ss[i].v]);
    		} else if ( vis[ss[i].v] ) {
    			low[x] = Min(low[x] ,dfn[ss[i].v] ) ;
    		}
    	}
    	if ( low[x] == dfn[x] ) {
    		int y ;
    		while ((y = sta[pos--])) {
    			flag[y] = x;
    			vis[y] = false;
    			if ( x == y ) break;
    			sum[x] += sum[y];
    		} 
    	}
    }
    
    void toposort() {
    	queue<int >que;
    	for (int i = 1 ; i <= n ; i ++ ) {
    		if ( flag[i] == i && !in[i] ) {
    			que.push(i);
    			dp[i] = sum[i] ;
    		}
    	}
    	while( !que.empty() ) {
    		int top = que.front() ; que.pop() ;
    		for (int i = h[top] ; ~i ; i = s[i].nxt ) {
    			dp[s[i].v] = Max(dp[s[i].v] ,dp[top] + sum[s[i].v]) ;
    			in[s[i].v] --;
    			if ( !in[s[i].v] ) que.push(s[i].v) ;
    		}
    	}
    }
    
    int main() {
    	init() ; int u, v ;
    	scanf("%d %d",&n ,&m ) ;
    	for (int i = 1 ; i <= n ; i ++ ) {
    		scanf("%d",&sum[i]);
    	}
    	for ( int i = 1 ; i <= m ; i ++ ) {
    		scanf("%d %d",&u ,&v ) ;
    		add_edge(u ,v ) ;
    	}
    	for (int i = 1 ; i <= n ; i ++ ) {
    		if ( !dfn[i]) tarjan(i);
    	}
    	for (int i = 1 ; i <= m ; i ++ ) {
    		int x = flag[ss[i].u] ,y = flag[ss[i].v] ;
    		if ( x != y ) {
    			s[++cnt1].u = x ;
    			s[cnt1].v = y ;
    			s[cnt1].nxt = h[x] ;
    			h[x] = cnt1;
    			in[y] ++;
    		}
    	}
    	toposort() ;
    	int maxx = -0x3f3f3f3f ;
    	for (int i = 1 ; i <= n ; i ++ ) {
    		if ( dp[i] > maxx ) maxx = dp[i] ;
    	}
    	printf("%d
    ",maxx );
    	return 0;
    }
    
  • 相关阅读:
    网站安全编程 黑客入侵 脚本黑客 高级语法入侵 C/C++ C# PHP JSP 编程
    【算法导论】贪心算法,递归算法,动态规划算法总结
    cocoa2dx tiled map添加tile翻转功能
    8月30日上海ORACLE大会演讲PPT下载
    【算法导论】双调欧几里得旅行商问题
    Codeforces Round #501 (Div. 3) B. Obtaining the String (思维,字符串)
    Codeforces Round #498 (Div. 3) D. Two Strings Swaps (思维)
    Educational Codeforces Round 89 (Rated for Div. 2) B. Shuffle (数学,区间)
    洛谷 P1379 八数码难题 (BFS)
    Educational Codeforces Round 89 (Rated for Div. 2) A. Shovels and Swords (贪心)
  • 原文地址:https://www.cnblogs.com/Nlifea/p/11745922.html
Copyright © 2011-2022 走看看