【BZOJ1179】atm,tarjan缩点+最长路径

Time:2016.05.21
Author:xiaoyimi
转载注明出处谢谢


传送门
思路:
题目中是一个带点权的有向图,如果这是一个没有环的图那么问题就很简单,拓扑或者直接求最长(短)路径什么的信手拈来,但是它有环,这就要求我们对图进行重构,把它搞成一个有向无环图,然后求得极值路径就可以了
tarjan缩点重构图,然后在重构图上跑最长(短)路,最后的答案就是max(dis[有酒吧的点])
注意:
1.还是要注意,重构图和原图不能搞混了……
2.如果跑最长路的话,dis不要初始化为0,可能出现起点周围的点权都是0,直接导致从起点搜索一遍,没有点入队的情况
代码:

#include<bits/stdc++.h>
using namespace std;
#define M 500005
int in()
{
    int t=0;char ch=getchar();
    while (!isdigit(ch)) ch=getchar();
    while (isdigit(ch)) t=(t<<1)+(t<<3)+ch-48,ch=getchar();
    return t;
}
int n=in(),m=in(),s,p,tot,cnt;
struct edge{int u,v,next;}e[M],E[M];
int first[M],c[M],dfn[M],low[M],belong[M],First[M],C[M],dis[M];
bool is_end[M],vis[M];
stack<int>S;
queue<int>Q;
void add(int y,int x){e[++tot]=(edge){x,y,first[x]};first[x]=tot;}
void Add(int x,int y){E[++tot]=(edge){x,y,First[x]};First[x]=tot;}
void dfs(int x)
{
    dfn[x]=low[x]=++cnt;
    S.push(x);
    vis[x]=1;
    for (int i=first[x];i;i=e[i].next)
        if (!dfn[e[i].v])
            dfs(e[i].v),
            low[x]=min(low[x],low[e[i].v]);
        else if (vis[e[i].v])
            low[x]=min(low[x],dfn[e[i].v]);
    if (dfn[x]==low[x])
    {
        C[x]=0;
        for (int y=-1;y!=x;y=S.top(),S.pop())
            belong[S.top()]=x,
            C[x]+=c[S.top()],
            vis[S.top()]=0;
    }
}
main()
{
    for (int i=1;i<=m;i++) add(in(),in());
    for (int i=1;i<=n;i++) c[i]=in();
    s=in();p=in();
    for (int i=1;i<=p;i++) is_end[in()]=1;
    tot=0;
    for (int i=1;i<=n;i++)
        if (!dfn[i]) dfs(i);
    for (int i=1;i<=n;i++)
        for (int j=first[i];j;j=e[j].next)
            if (belong[i]!=belong[e[j].v])
                Add(belong[i],belong[e[j].v]);
    memset(dis,63,sizeof(dis));
    Q.push(belong[s]);vis[belong[s]]=1;
    dis[belong[s]]=-C[belong[s]];
    while (!Q.empty())
    {
        int x=Q.front();
        Q.pop();
        vis[x]=0;
        for (int i=First[x];i;i=E[i].next)
            if (dis[x]-C[E[i].v]<dis[E[i].v])
            {
                dis[E[i].v]=dis[x]-C[E[i].v];
                if (!vis[E[i].v]) Q.push(E[i].v),vis[E[i].v]=1;
            }
    }
    int ans=0;
    for (int i=1;i<=n;i++)
        if (is_end[i]) ans=min(ans,dis[belong[i]]);
    printf("%d",-ans);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值