您的位置:首页 > 其它

【Bzoj1179】[Apio2009]抢掠计划atm

2017-11-08 14:56 211 查看
时间限制:1S / 空间限制:256MB

【在线测试提交传送门】

【问题描述】



【输入格式】

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


【输出格式】

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


【输入样例1】

6 7
1 2
2 3
3 5
2 4
4 1
2 6
6 5
10
12
8
16
1 5
1 4
4
3
5
6


【输出样例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 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);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: