【Bzoj1179】[Apio2009]抢掠计划atm

来源:互联网 发布:民族政策知乎 编辑:程序博客网 时间:2024/05/23 15:37

时间限制:1S / 空间限制:256MB

【在线测试提交传送门】

【问题描述】

这里写图片描述

【输入格式】

第一行包含两个整数N、M。N表示路口的个数,M表示道路条数。接下来M行,每行两个整数,这两个整数都在1到N之间,第i+1行的两个整数表示第i条道路的起点和终点的路口编号。接下来N行,每行一个整数,按顺序表示每个路口处的ATM机中的钱数。接下来一行包含两个整数S、P,S表示市中心的编号,也就是出发的路口。P表示酒吧数目。接下来的一行中有P个整数,表示P个有酒吧的路口的编号

【输出格式】

输出一个整数,表示Banditji从市中心开始到某个酒吧结束所能抢劫的最多的现金总数。

【输入样例1】

6 71 22 33 52 44 12 66 510128161 51 44356

【输出样例1】

47

【说明】

50%的输入保证N, M≤3000。所有的输入保证N, M≤500000。每个ATM机中可取的钱数为一个非负整数且不超过4000。输入数据保证你可以从市中心沿着Siruseri的单向的道路到达其中的至少一个酒吧。

【题目来源】

Bzoj1179 Apio2009

【解题思路】

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

【参考代码】

#include<bits/stdc++.h>using namespace std;#define M 500005int 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);}
原创粉丝点击