[APIO2009]抢掠计划 tarjan缩点+spfa BZOJ1179

题目描述

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

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

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

[APIO2009]抢掠计划 tarjan缩点+spfa BZOJ1179

市中心在路口 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

说明

50%的输入保证 N, M<=3000。所有的输入保证 N, M<=500000。每个 ATM 机中可取的钱数为一个非负整数且不超过 4000。

输入数据保证你可以从市中心 沿着 Siruseri 的单向的道路到达其中的至少一个酒吧。

[APIO2009]抢掠计划 tarjan缩点+spfa BZOJ1179

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<map>
#include<set>
#include<vector>
#include<queue>
#include<bitset>
#include<ctime>
#include<time.h>
#include<deque>
#include<stack>
#include<functional>
#include<sstream>
//#include<cctype>
//#pragma GCC optimize(2)
using namespace std;
#define maxn 700005
#define inf 0x7fffffff
//#define INF 1e18
#define rdint(x) scanf("%d",&x)
#define rdllt(x) scanf("%lld",&x)
#define rdult(x) scanf("%lu",&x)
#define rdlf(x) scanf("%lf",&x)
#define rdstr(x) scanf("%s",x)
#define mclr(x,a) memset((x),a,sizeof(x))
typedef long long  ll;
typedef unsigned long long ull;
typedef unsigned int U;
#define ms(x) memset((x),0,sizeof(x))
const long long int mod = 1e9 + 7;
#define Mod 1000000000
#define sq(x) (x)*(x)
#define eps 1e-5
typedef pair<int, int> pii;
#define pi acos(-1.0)
//const int N = 1005;
#define REP(i,n) for(int i=0;i<(n);i++)
typedef pair<int, int> pii;

inline int rd() {
	int x = 0;
	char c = getchar();
	bool f = false;
	while (!isdigit(c)) {
		if (c == '-') f = true;
		c = getchar();
	}
	while (isdigit(c)) {
		x = (x << 1) + (x << 3) + (c ^ 48);
		c = getchar();
	}
	return f ? -x : x;
}


ll gcd(ll a, ll b) {
	return b == 0 ? a : gcd(b, a%b);
}
int sqr(int x) { return x * x; }



/*ll ans;
ll exgcd(ll a, ll b, ll &x, ll &y) {
	if (!b) {
		x = 1; y = 0; return a;
	}
	ans = exgcd(b, a%b, x, y);
	ll t = x; x = y; y = t - a / b * y;
	return ans;
}
*/
int n, m;
int idx;
int col[maxn], val[maxn];
int head[maxn];
int sk[maxn], top;
int dfn[maxn], low[maxn];
int tot;
int vis[maxn];
int sum[maxn];
int num[maxn];
int u[maxn], v[maxn];
int S, P;

struct node {
	int u, v, nxt, w;
}e[maxn<<1];

int cnt;
void add1(int u, int v) {
	e[++cnt].v = v; e[cnt].nxt = head[u]; head[u] = cnt;
}
void add2(int u, int v, int w) {
	e[++cnt].v = v; e[cnt].u = u; e[cnt].w = w;
	e[cnt].nxt = head[u]; head[u] = cnt;
}

void tarjan(int x) {
	sk[++top] = x; vis[x] = 1; low[x] = dfn[x] = ++idx;
	for (int i = head[x]; i; i = e[i].nxt) {
		int v = e[i].v;
		if (!dfn[v]) {
			tarjan(v); low[x] = min(low[x], low[v]);
		}
		else if (vis[v]) {
			low[x] = min(low[x], dfn[v]);
		}
	}
	if (dfn[x] == low[x]) {
		tot++;
		while (sk[top + 1] != x) {
			col[sk[top]] = tot; sum[tot] += val[sk[top]];
			vis[sk[top--]] = 0; num[tot]++;
		}
	}
}
queue<int>q;
//int q[maxn];
int dis[500005];
void spfa() {
	mclr(dis, 0x3f);
	int st = col[S];
	dis[st] = -sum[st];
	q.push(st);
	while (!q.empty()) {
		int tmp = q.front(); q.pop();
		vis[tmp] = 0;
		for (int i = head[tmp]; i; i = e[i].nxt) {
			int to = e[i].v;
			if (dis[to] > dis[tmp] + e[i].w) {
				dis[to] = dis[tmp] + e[i].w;
				if (!vis[to]) {
					q.push(to); vis[to] = 1;
				}
			}
		}
	}
}

int main()
{
//	ios::sync_with_stdio(0);
	n = rd(); m = rd();
	for (int i = 1; i <= m; i++) {
		u[i] = rd(); v[i] = rd();
		add1(u[i], v[i]);
	}
	for (int i = 1; i <= n; i++)rdint(val[i]);// 点权
	// sum[]为缩完点之后的新图权值
	for (int i = 1; i <= n; i++) {
		if (!dfn[i])tarjan(i);
	}
	ms(head); ms(e); ms(vis);
	cnt = 0;
	for (int i = 1; i <= m; i++) {
		if (col[u[i]] != col[v[i]]) {
			add2(col[u[i]], col[v[i]], -sum[col[v[i]]]);
		}
	}
	S = rd();
	spfa();
	P = rd();
	ll ans = 0;
	for (int i = 1; i <= P; i++) {
		int dx = rd();
		if (ans < -dis[col[dx]])ans = -dis[col[dx]];
	}
	cout << ans << endl;
	return 0;
}

 

上一篇:银行 ATM 系统项目


下一篇:测试-001