洛谷P3627[APOI2009] (讨厌的)抢掠计划

时间:2023-11-25 22:26:20

题目描述

Siruseri 城中的道路都是单向的。不同的道路由路口连接。按照法律的规定, 在每个路口都设立了一个 Siruseri 银行的 ATM 取款机。令人奇怪的是,Siruseri 的酒吧也都设在路口,虽然并不是每个路口都设有酒吧。

Banditji 计划实施 Siruseri 有史以来最惊天动地的 ATM 抢劫。他将从市中心 出发,沿着单向道路行驶,抢劫所有他途径的 ATM 机,最终他将在一个酒吧庆 祝他的胜利。

使用高超的黑客技术,他获知了每个 ATM 机中可以掠取的现金数额。他希 望你帮助他计算从市中心出发最后到达某个酒吧时最多能抢劫的现金总数。他可 以经过同一路口或道路任意多次。但只要他抢劫过某个 ATM 机后,该 ATM 机 里面就不会再有钱了。 例如,假设该城中有 6 个路口,道路的连接情况如下图所示:

洛谷P3627[APOI2009] (讨厌的)抢掠计划

市中心在路口 1,由一个入口符号→来标识,那些有酒吧的路口用双圈来表

示。每个 ATM 机中可取的钱数标在了路口的上方。在这个例子中,Banditji 能抢 劫的现金总数为 47,实施的抢劫路线是:1-2-4-1-2-3-5。

输入输出格式

输入格式:

第一行包含两个整数 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


说说我对这道题的看法?

讨厌死了

首先我写了非常长的时间 然后DKY同学坐我旁边20minA了这道题(ri)

被嘲讽一波之后还是决定考完NOIP之后退役

思路:

缩点 然后跑拓补序DP 然后酒吧扫一遍 完事

但是我莫名其妙在为什么不用判重边这件事上郁闷了好久(MD

为什么不用判重边?你跑拓补序DP的时候是根据当前点的总和加上下一个点的点权去尝试更新的

于是你就算重复连了边 你也只会在第一次判断的时候更新 后面的重边不会影响你的结果

入度也该减的就减 反正保证他能推过去就行了

还有个小细节就是只用从起点跑TARJAN就行了 起点去不了的地方对答案不产生影响

然后?NM有个地方rd[col[y]]写成了rd[y]导致20min

CXK NMSL

上代码:

#include<bits/stdc++.h>
#define MAXN 500010
#define MAXM 500010 using namespace std; int n,m,a[MAXN],b[MAXN];
int dfn[MAXN],low[MAXN],head[MAXN],ectr;
int sta[MAXN],tp,col[MAXN],num,cnt,ans;
int f[MAXN],cash[MAXN],scash[MAXN],str,rd[MAXN];
bool ins[MAXN],bar[MAXN];
queue<int> q;
struct Edge{
int to,nxt;
}edge[MAXM];
struct Data{
int from,to;
}data[MAXM]; void addedge(int from,int to){
ectr++;
edge[ectr].to=to;
edge[ectr].nxt=head[from];
head[from]=ectr;
} inline int read() {
int x=;char ch=getchar();
while(ch<''||ch>'')ch=getchar();
while(ch>=''&&ch<='')x=(x<<)+(x<<)+ch-'',ch=getchar();
return x;
} void tarjan(int x){
dfn[x] = low[x] = ++num;
sta[++tp] = x;ins[x]=true;
for(int i=head[x];i;i=edge[i].nxt){
int y=edge[i].to;
if(!dfn[y]){
tarjan(y);
low[x] = min(low[x],low[y]);
}
else if(ins[y]){
low[x]=min(low[x],dfn[y]);
}
}
if(dfn[x]==low[x]){
int y=;
cnt++;
do{
y=sta[tp--],ins[y]=false;
col[y] = cnt;
scash[col[y]]+=cash[y];
}while (x!=y);
}
} void topo(){
q.push(col[str]);
f[col[str]] = scash[col[str]];
while(!q.empty()){
int x=q.front();
q.pop();
for(int i=head[x];i;i=edge[i].nxt){
int y=edge[i].to;
f[y] = max(f[y],f[x] + scash[y]);
if(!--rd[y]) q.push(y);
}
}
} int main(){
n=read(),m=read();
for(int i=;i<=m;i++){
data[i].from=read(),data[i].to=read();
addedge(data[i].from,data[i].to);
}
for(int i=;i<=n;i++){
cash[i]=read();
}
str=read();
int DKY=read();
for(int i=;i<=DKY;i++){
int tra1=read();
bar[tra1]=true;
} tarjan(str); for(int i=;i<=n;i++) head[i]=;
ectr=; for(int i=;i<=m;i++){
int x=data[i].from,y=data[i].to;
if(!dfn[x] || !dfn[y]) continue;
if(col[x] == col[y]) continue;
addedge(col[x],col[y]);
rd[col[y]]++; //对 就是这 20min NMSL
} topo(); for(int i=;i<=n;i++){
if(bar[i]){
ans=max(ans,f[col[i]]);
}
}
cout<<ans<<endl;
return ;
}

TAG : SIN_XIII ⑨