• 图论_FatherChristmasFlymouse(Tarjan+dijkstra or spfa)



    堆优化Dij VS Spfa 堆优化Dij小胜一筹。

    题目名字:Father Christmas flymouse (POJ 3160)
    这题可以说是图论做的比较畅快的一题,比较综合,很想说一说。
    首先题目大概意思就是走图拿点权,问说最大能拿到多少。一开始看到这题第一反应是挺好做的吧,因为每个点可以走多次,但是点权只能拿一次(可以路过不拿),这个个人觉得难度系数一下就降低了(如果每个点只能过一次就真的不会了。。。)于是乎,我们可以这样想,想要拿走的最大,肯定不想拿负点权,又因为每个点可以只走不拿,那负点权直接输入赋0就可以了,反正肯定只是路过不去拿,那干脆赋0,这样写的时候都拿也等于没有拿,点权问题解决了,接下来可以说就可以愉快的跑最短路了,其实是最长路,但是道理是一样的,能跑最短路肯定也能最长路,只是比较的符号问题。但是跑最短路之前,可以不可以想一想有没有神奇的优化,答案是有的,因为有向图,所以我们可以缩点(考虑tarjan,笔者也只会这个。。而且笔者感觉必须缩点,因为一旦有环(因为负值全部被赋0),那最长路最跑越长就出不来了),缩点染色完重新建图,合并点权(一定要小心,之前合并错了一次,合并一错肯定就是WA不用说)就是愉快的最短路了。

    下面符个代码,第一次写题目博客有点激动,很不熟练,望看官指点,不胜感谢。
    (个人习惯染色从1开始,这也是学习tarjan博客博客的一个写法,所以设了一个0为总原点,能到染色完的各个强联通分量)

    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <cstdio>
    #include <vector>
    #include <queue>
    #define ms(a,b) memset((a),(b),sizeof(a))
    #define fi first
    #define se second
    #define mp make_pair
    using namespace std;
    
    typedef pair<int,int> pii;
    const int N = 3e4 + 16;
    vector<int> sono[N], sonn[N];
    
    int n, m;
    int sum, top, depth;
    bool vis[N], _vis[N];
    int low[N], dnf[N], sta[N], col[N];
    int valn[N], valo[N];
    int dis[N];
    
    void tarjan( int u )
    {
    	low[u] = dnf[u] = ++depth;
    	sta[++top] = u;
    	vis[u] = 1;
    	
    	for ( int i = 0; i < sono[u].size(); i ++ )
    	{
    		int v = sono[u][i];
    		if ( !dnf[v] )
    		{
    			tarjan(v);
    			low[u] = min( low[u], low[v] );
    		}
    		else
    		{
    			if ( vis[v] )
    			{
    				low[u] = min( low[u], low[v] );
    			}
    		}
    	}
    	
    	if ( low[u] == dnf[u] )
    	{
    		vis[u] = 0;
    		col[u] = ++sum;
    		while ( sta[top] != u )
    		{
    			vis[ sta[top] ] = 0;
    			col[ sta[top--] ] = sum;
    		}
    		top --;
    	}
    }
    
    void Build()
    {
    	for ( int i = 1; i <= sum; i ++ )
    		sonn[0].push_back(i);
    	
    	for ( int i = 1; i <= n; i ++ )
    		valn[ col[i] ] += valo[ i ];
    
    	for ( int i = 1; i <= n; i ++ )
    	{
    		for ( int j = 0; j < sono[i].size(); j ++ )
    		{
    			if ( col[i] != col[ sono[i][j] ] )
    				sonn[ col[i] ].push_back( col[ sono[i][j] ] );
    		}
    	}
    }
    
    
    int dij( int s )
    {
    	priority_queue< pii > q;
    	ms(dis,0);
    	dis[s] = 0;
    	q.push( mp(0,s) );
    	
    	while ( !q.empty() )
    	{
    		pii now = q.top();
    		q.pop();
    		
    		if ( now.fi < dis[now.se] ) continue;
    		
    		for ( int i = 0; i < sonn[now.se].size(); i ++ )
    		{
    			int v = sonn[now.se][i];
    			if ( dis[v] < now.fi + valn[v] )
    			{
    				dis[v] = now.fi + valn[v];
    				q.push( mp(dis[v],v) );
    			}
    		}
    	}
    	
    	int ans = 0;
    	for ( int i = 1; i <= sum; i ++ )
    	{
    		ans = max( ans, dis[i] );
    	}
    	return ans;
    }
    
    int spfa( int s )
    {
    	queue<int> q;
    	ms(dis,0);
    	dis[s] = 0;
    	_vis[s] = 1;
    	q.push(s);
    	
    	while ( !q.empty() )
    	{
    		int now = q.front();
    		q.pop();
    		_vis[now] = 0;
    		
    		for ( int i = 0; i < sonn[now].size(); i ++ )
    		{
    			int v = sonn[now][i];
    			if ( dis[v] < dis[now] + valn[v] )
    			{
    				dis[v] = dis[now] + valn[v];
    				if ( !_vis[v] )
    				{
    					_vis[v] = 1;
    					q.push(v);
    				}
    			}
    		}
    	}
    	
    	int ans = 0;
    	for ( int i = 1; i <= sum; i ++ )
    	{
    		ans = max( ans, dis[i] );
    	}
    	return ans;
    }
    
    void init( int n )
    {
    	sum = top = depth = 0;
    	for ( int i = 0; i <= n+1; i ++ )
    	{
    		sonn[i].clear();
    		sono[i].clear();
    		low[i] = dnf[i] = 0;
    		sta[i] = vis[i] = col[i] = 0;
    		dis[i] = 0;
    		valn[i] = valo[i] = 0;
    	}
    }
    
    int main()
    {
    	while ( ~scanf("%d%d", &n, &m) )
    	{
    		init(n);
    		
    		for ( int i = 1; i <= n; i ++ )
    		{
    			scanf("%d", &valo[i]);
    			if ( valo[i] < 0 ) valo[i] = 0;
    		}
    		
    		for ( int i = 0; i < m; i ++ )
    		{
    			int u, v;
    			scanf("%d%d", &u, &v);
    			u++;
    			v++;
    			sono[u].push_back(v);
    		}
    		
    		for ( int i = 1; i <= n; i ++ )
    			if ( !dnf[i] )
    				tarjan(i);
    				
    		Build();
    		int ans1 = dij(0);;
    //		int ans2 = spfa(0);
    //		printf("%d
    %d
    ", ans1, ans2);
    		printf("%d
    ", ans1);
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    条件运算符
    类型
    c#
    打印菱形
    关于隐藏控制器的导航条的问题
    怎么去掉Xcode工程中的某种类型的警告 Implicit conversion loses integer precision: 'NSInteger' (aka 'long') to 'int32
    如何在导航条的button点击变换时,切换对应的控制器
    如何只选择一个
    重写TabBar遇到的按钮不显示的问题
    ASI和AFN的区别
  • 原文地址:https://www.cnblogs.com/FormerAutumn/p/9387762.html
Copyright © 2020-2023  润新知