POJ 3160 Father Christmas flymouse

大意:Flymouse到达一个寝室时,可以选择进入寝室、发放礼物、倾听接收礼物或者默默的绕开这个寝室,可能会多次经过同一个寝室,但绝不会第二次进入该寝室。求:在发放礼物整个过程中,收获的最大安慰指数是多少。

思路:首先将有向图缩点,缩点后,重构图每个点内的权值为该强连通分量的权值之和(负权值赋值为0,因为可以绕过去),然后在有向无环图上找最长路径,DP、SPFA均可。

 

#include <iostream>  
#include <cstdlib>  
#include <cstring>  
#include <cstdio>  
#include <queue>  
using namespace std;  
  
const int maxn = 30010;  
const int maxm = 150010;  
const int INF = 0x3f3f3f3f;
  
struct Edge  
{  
    int v, w;  
    int next;  
}edge[maxm], edge2[maxm];  
  
int n, m;
int cnt, cnt2;
int scnt, top, tot;
  
int first[maxn], low[maxn], dfn[maxn], stack[maxn], ins[maxn];  
int d[maxn];  
int first2[maxn];  
int belong[maxn];  
int cost[maxn];

int w[maxn];

void init()  
{  
    cnt = cnt2 = 0;  
    scnt = top = tot = 0;  
    memset(first, -1, sizeof(first));  
    memset(first2, -1, sizeof(first2));  
    memset(dfn, 0, sizeof(dfn));  
    memset(ins, 0, sizeof(ins));
    memset(cost, 0, sizeof(cost));
}

void read_graph(int u, int v)
{  
    edge[cnt].v = v; 
    edge[cnt].next = first[u], first[u] = cnt++;  
}  
  
void read_graph2(int u, int v)  
{  
    edge2[cnt2].v = v; 
    edge2[cnt2].next = first2[u], first2[u] = cnt2++;  
}  
  
void dfs(int u)  
{  
    int v;  
    dfn[u] = low[u] = ++tot;  
    stack[top++] = u;  
    ins[u] = 1;  
    for(int e = first[u]; e != -1; e = edge[e].next)  
    {  
        v = edge[e].v;  
        if(!dfn[v])  
        {  
            dfs(v);  
            low[u] = min(low[u], low[v]);  
        }  
        else if(ins[v])  
        {  
            low[u] = min(low[u], dfn[v]);  
        }  
    }  
    if(dfn[u] == low[u])  
    {  
        scnt++;  
        do  
        {  
            v = stack[--top];  
            belong[v] = scnt;  
            ins[v] = 0;
            cost[scnt] += w[v];
        }while(u != v);  
    }  
}  
  
void Tarjan()  
{  
    for(int v = 1; v <= n; v++) if(!dfn[v])  
        dfs(v);  
}  
  
void read_case()  
{  
    init();  
    for(int i = 1; i <= n; i++)
    {
        scanf("%d", &w[i]);
        if(w[i] < 0) w[i] = 0;
    }
    while(m--)
    {  
        int u, v, w;  
        scanf("%d%d", &u, &v); u++; v++;
        read_graph(u, v);  
    }
}  

void build()  
{ 
    for(int u = 1; u <= n; u++)  
    {  
        for(int e = first[u]; e != -1; e = edge[e].next)
        {  
            int v = edge[e].v, w = edge[e].w;
            if(belong[u] != belong[v])
            {
                read_graph2(belong[u], belong[v]);
            }
        }
    }
}

bool vis[maxn];

int dp(int u)
{
    int &ans = d[u];
    if(vis[u]) return ans;
    ans = cost[u];
    for(int e = first2[u]; e != -1; e = edge2[e].next)
    {
        int v = edge2[e].v;
        ans = max(ans, dp(v) + cost[u]);
    }
    return ans;
}

int cal()
{
    memset(vis, 0, sizeof(vis));
    memset(d, 0, sizeof(d));
    
    int ans = 0;
    for(int i = 1; i <= scnt; i++) ans = max(ans, dp(i));
    return ans;
}

void solve()
{
    read_case();
    Tarjan();
    build();
    int ans = cal();
    printf("%d\n", ans);
}

int main()  
{  
    while(~scanf("%d%d", &n, &m))
    {
        solve();  
    }  
    return 0;  
}
View Code

 

 

 

转载于:https://www.cnblogs.com/Buck-Meister/archive/2013/05/10/3071144.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值