poj 3160 Father Christmas flymouse 强连通+dp

首先我们可以确定的是,对于val值小于0的节点都变成0.   假设一个集合内2个房间都能任意到达,那么我就可以吧集合内的所有点的价值都取到,并且可以达到任一点。实际上集合内的每个点是相同的,这样的集合就是一个强连通分量。 那么我们就可以用tarjin算法进行强连通缩点, 最后形成一个dag的图。在dag的图上面进行dp。可以先用拓扑排序后dp。或者建反响边记忆化搜索 。

VIEW  CDDE

//#pragma comment(linker, "/STACK:102400000,102400000")
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<queue>
#include<stack>
#include<string>
#include<cstring>
#include<map>
#include<vector>
#include<set>
#include<ctime>
#include<stdlib.h>
using namespace std;
const int mmax= 30010;
const int mod=1000000007;
typedef long long LL;

struct node
{
    int st,en;
    int next;
}E[150010];
int p[mmax],fa[mmax];
int num;
void init()
{
    memset(p,-1,sizeof p);
    num=0;
}
void add(int st,int en)
{
    E[num].st=st;
    E[num].en=en;
    E[num].next=p[st];
    p[st]=num++;
}
int find(int x)
{
    if(x==fa[x])
        return x;
    return fa[x]=find(fa[x]);
}
int times,pp;
int low[mmax],dfn[mmax],Q[mmax];
bool instack[mmax];
void tarjin(int u)
{
    dfn[u]=low[u]=++times;
    Q[++pp]=u;
    instack[u]=1;
    for(int i=p[u];i+1;i=E[i].next)
    {
        int v=E[i].en;
        if(!dfn[v])
        {
            tarjin(v);
            if(low[u]>low[v])
                low[u]=low[v];
        }
        else if(instack[v])
            low[u]=min(low[u],dfn[v]);
    }

    if(dfn[u]==low[u])
    {
        while(pp)
        {
            int x=Q[pp--];
            instack[x]=0;
            if(x==u)
                break;
            int xx=find(x);
            fa[xx]=u;
        }
    }
}

LL dp[mmax],val[mmax];
LL sum[mmax];
int in[mmax];
bool vis[mmax];

struct node2
{
    int st,en;
    int next;
}e[150010];
int p_[mmax];
int num_;
void init_()
{
    memset(p_,-1,sizeof p_);
    num_=0;
}
void add_(int st,int en)
{
    e[num_].st=st;
    e[num_].en=en;
    e[num_].next=p_[st];
    p_[st]=num_++;
}
queue<int>q;
int main()
{
    int n,m;
    //freopen("in.txt","r",stdin);
    while(cin>>n>>m)
    {
        init();
        memset(dp,0,sizeof dp);
        memset(in,0,sizeof in);
        memset(sum,0,sizeof sum);
        for(int i=1;i<=n;i++)
            fa[i]=i;
        while(!q.empty())
            q.pop();
        for(int i=1;i<=n;i++)
            scanf("%lld",&val[i]);
        for(int i=0;i<m;i++)
        {
            int u,v;
            scanf("%d %d",&u,&v);
            u++,v++;
            add(u,v);
        }
        times=pp=0;
        memset(instack,0,sizeof instack);
        memset(dfn,0,sizeof dfn);
        for(int i=1;i<=n;i++)
        {
            if(!dfn[i])
                tarjin(i);
        }

        init_();
        memset(in,0,sizeof in);
        for(int i=1;i<=n;i++)
            sum[find(i)]+= val[i]>0? val[i]:0 ;
        for(int i=1;i<=n;i++)
        {
            int u=find(i);
            for(int j=p[i];j+1;j=E[j].next)
            {
                int v=find(E[j].en);
                if(u!=v)
                    add_(u,v);
            }
        }
        memset(vis,0,sizeof vis);
        for(int i=1;i<=n;i++)
            if(i==find(i)) add_(0,i);
        q.push(0);
        vis[0]=1;
        while(!q.empty())
        {
            int x=q.front();
            q.pop();
            vis[x]=0;
            for(int i=p_[x];i+1;i=e[i].next)
            {
                int v=e[i].en;
                if(dp[v] < dp[x]+ sum[v])
                {
                    dp[v]=dp[x]+sum[v];
                    if(!vis[v])
                    {
                        q.push(v);
                        vis[v]=1;
                    }
                }
            }
        }
        LL ans=0;
        for(int i=1;i<=n;i++)
            ans=ans<dp[i]?dp[i]:ans;
        cout<<ans<<endl;
    }
    return 0;
}
时间: 2024-07-30 10:13:06

poj 3160 Father Christmas flymouse 强连通+dp的相关文章

POJ 3160 Father Christmas flymouse

Father Christmas flymouse Time Limit: 1000ms Memory Limit: 131072KB This problem will be judged on PKU. Original ID: 316064-bit integer IO format: %lld      Java class name: Main After retirement as contestant from WHU ACM Team, flymouse volunteered

poj 3160 Father Christmas flymouse【强连通 DAG spfa 】

和上一道题一样,可以用DAG上的动态规划来做,也可以建立一个源点,用spfa来做 1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #include<stack> 6 #include<vector> 7 using namespace std; 8 9 const int maxn = 5005; 10 int n,

POJ——T3160 Father Christmas flymouse

Time Limit: 1000MS   Memory Limit: 131072K Total Submissions: 3496   Accepted: 1191 缩点,然后每个新点跑一边SPFA 思路不难 ,注意细节~ 1 #include <algorithm> 2 #include <cstring> 3 #include <cstdio> 4 #include <queue> 5 6 using namespace std; 7 8 const

【连通图|强连通分量+dfs】POJ-3160 Father Christmas flymouse

Father Christmas flymouse Time Limit: 1000MS Memory Limit: 131072K Description After retirement as contestant from WHU ACM Team, flymouse volunteered to do the odds and ends such as cleaning out the computer lab for training as extension of his contr

POJ 3592 Instantaneous Transference(强连通+DP)

POJ 3592 Instantaneous Transference 题目链接 题意:一个图,能往右和下走,然后有*可以传送到一个位置,'#'不能走,走过一个点可以获得该点上面的数字值,问最大能获得多少 思路:由于有环先强连通缩点,然后问题转化为dag,直接dp即可 代码: #include <cstdio> #include <cstring> #include <vector> #include <algorithm> #include <sta

POJ 3254 Corn Fields 状态压缩DP (C++/Java)

http://poj.org/problem?id=3254 题目大意: 一个农民有n行m列的地方,每个格子用1代表可以种草地,而0不可以.放牛只能在有草地的,但是相邻的草地不能同时放牛, 问总共有多少种方法. 思路: 状态压缩的DP. 可以用二进制数字来表示放牧情况并判断该状态是否满足条件. 这题的限制条件有两个: 1.草地限制. 2.相邻限制. 对于草地限制,因为输入的时候1是可以种草地的. 以"11110"草地分析,就只有最后一个是不可以种草的.取反后得00001  .(为啥取反

POJ 3071 Football(简单 概率DP)

Football 原文链接:http://blog.csdn.net/xuechelingxiao/article/details/38520105 大意:2^n 个球队进行单场淘汰赛,每两只球队之间比赛会有胜负的概率,问最后谁夺冠的概率最大. 思路:简单的概率DP问题,主要是怎么处理哪两个球队比赛的问题. DP方程为 dp[i][j] = ∑(dp[i-1][j]*dp[i-1][k]*p[j][k]); //dp[i][j]表示第 i 轮的时候,第 j 支队伍赢的概率.. 对于其中位运算,可

POJ 1185 炮兵阵地 状压dp

http://poj.org/problem?id=1185 经典题目不必多说,直接贴代码. 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 6 int n, m, cnt, size; 7 int a[110], st[70], ct[70]; 8 char str[15]; 9 int f[110][70][70]; 10 void init(

POJ 3132 Sum of Different Primes DP背包

http://poj.org/problem?id=3132 题意: 给定n和k,问用恰好k个不同的质数来表示n的方案数. 分析: n和k都很小.反正就是个背包,选k个物品恰好填满n即可. 1 #include<cstdio> 2 #include<cstring> 3 using namespace std; 4 5 bool dp[1200][15]; 6 int ct[1200][15]; 7 int p[1200]; 8 bool a[1200]; 9 int n, k,