bzoj1179: [Apio2009]Atm

链接

  http://www.lydsy.com/JudgeOnline/problem.php?id=1179

题解

  这道题目并没有看上去的那么好做啊。
  首先肯定 tarjan 缩点,所完之后是一个 DAG
  然后题目问题以某个点为开头的最长链,这个东西貌似不好dp吧….
  所以只能上spfa。不太好调,细节挺多的。

代码

//tarjan+dp
#include <cstdio>
#include <algorithm>
#include <queue>
#define maxn 1000010
using namespace std;
int N, M, head[maxn], to[maxn], nex[maxn], scc[maxn], stack[maxn], s[maxn], w[maxn],
    dfn[maxn], vis[maxn], low[maxn], u[maxn], v[maxn], rd[maxn], f[maxn],
    pub[maxn], S, tot, in[maxn];
queue<int> q;
inline void adde(int a, int b){to[++tot]=b;nex[tot]=head[a];head[a]=tot;}
inline int read(int x=0)
{
    char c=getchar();
    while(c<48 or c>57)c=getchar();
    while(c>=48 and c<=57)x=(x<<1)+(x<<3)+c-48,c=getchar();
    return x;
}
void tarjan(int pos)
{
    int p;
    dfn[pos]=low[pos]=++dfn[0];
    stack[++stack[0]]=pos;
    vis[pos]=1;
    for(p=head[pos];p;p=nex[p])
    {
        if(vis[to[p]]==0)tarjan(to[p]);
        if(vis[to[p]]==1)low[pos]=min(low[pos],low[to[p]]);
    }
    if(dfn[pos]==low[pos])
    {
        for(++scc[0];stack[stack[0]+1]!=pos;stack[0]--)
            scc[stack[stack[0]]]=scc[0],vis[stack[stack[0]]]=2;
    }
}
void dp()
{
    int i, x, p, m=-1;
    f[scc[S]]=w[scc[S]];
    q.push(scc[S]);in[scc[S]]=1;
    while(!q.empty())
    {
        in[x=q.front()]=0;q.pop();
        for(p=head[x];p;p=nex[p])
        {
            if(f[x]+w[to[p]]>f[to[p]])
            {
                f[to[p]]=f[x]+w[to[p]];
                if(!in[to[p]])q.push(to[p]),in[to[p]]=1;
            }
        }
    }
    for(i=1;i<=N;i++)if(pub[i])m=max(m,f[scc[i]]);
    printf("%d",m);
}
void init()
{
    int i, P, x;
    scanf("%d%d",&N,&M);
    for(i=1;i<=M;i++)u[i]=read(), v[i]=read(), adde(u[i],v[i]);
    for(i=1;i<=N;i++)w[i]=read();
    S=read(), P=read();
    for(i=1;i<=P;i++)x=read(), pub[x]=1;
    scc[0]=N;
    for(i=1;i<=N;i++)if(!vis[i])tarjan(i);
    for(i=1;i<=M;i++)if(scc[u[i]]^scc[v[i]])adde(scc[u[i]],scc[v[i]]),rd[scc[v[i]]]++;
    for(i=1;i<=N;i++)w[scc[i]]+=w[i];
}
int main()
{
    init();
    dp();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值