图论_FatherChristmasFlymouse(Tarjan+dijkstra or spfa)

Posted formerautumn

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了图论_FatherChristmasFlymouse(Tarjan+dijkstra or spfa)相关的知识,希望对你有一定的参考价值。

技术分享图片
堆优化Dij VS Spfa 堆优化Dij小胜一筹。

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

下面符个代码,第一次写题目博客有点激动,很不熟练,望看官指点,不胜感谢。

#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;
}



以上是关于图论_FatherChristmasFlymouse(Tarjan+dijkstra or spfa)的主要内容,如果未能解决你的问题,请参考以下文章

noip_最后一遍_2-图论部分

图论题目模板,和并查集:以后的图论题目就靠他了

图论_拓扑排序_练习1(优先队列小顶堆)

图论_拓扑排序

图论_链式前向星

图论_查并集