Description Input
第一行包含两个整数N、M。N表示路口的个数,M表示道路条数。接下来M行,每行两个整数,这两个整数都在1到N之间,第i+1行的两个整数表示第i条道路的起点和终点的路口编号。接下来N行,每行一个整数,按顺序表示每个路口处的ATM机中的钱数。接下来一行包含两个整数S、P,S表示市中心的编号,也就是出发的路口。P表示酒吧数目。接下来的一行中有P个整数,表示P个有酒吧的路口的编号 Output
输出一个整数,表示Banditji从市中心开始到某个酒吧结束所能抢劫的最多的现金总数。 Sample Input 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 Sample Output 47 HINT
50%的输入保证N, M<=3000。所有的输入保证N, M<=500000。每个ATM机中可取的钱数为一个非负整数且不超过4000。输入数据保证你可以从市中心沿着Siruseri的单向的道路到达其中的至少一个酒吧。
解题方法: 首先进行强连通缩点,维护每一个连通分量中,是否有一个点是酒吧,以及总钱数的多少。对缩点后的图进行拓扑排序,然后按照拓扑排序进行动态规划。记 dp[i]表示走到点 i 的最大获利,对于给定的起点属于的连通块有 dp[i]=money[i],其余点的初值都是 dp[i]=负无穷。对于一条边 i 连接 j,我们用 dp[i]+money[j]来更新 dp[j]。答案是满足一个连通块中至少有一个是酒吧的强连通分量中最大的 dp[i]。由于会爆栈,强连通分量算法要进行人工堆栈。时间复杂度 O(n+m)。
//bzoj 1179 tarjan spfa#include <bits/stdc++.h>using namespace std;const int maxn = 500005;int n, m, q, S, dfs_clock, cnt, scc, top, ans;int head1[maxn], head2[maxn], dp[maxn];int dfn[maxn], low[maxn], c[maxn], v[maxn], s[maxn], belong[maxn];bool inq[maxn], vis[maxn];struct edge{ int v, nxt; edge(){} edge(int v, int nxt) : v(v), nxt(nxt) {}}E1[maxn*2], E2[maxn*2];void init1(){ cnt = 0; memset(dp, 0, sizeof(dp)); memset(head1, -1, sizeof(head1));}void init2(){ cnt = 0; memset(head2, -1, sizeof(head2));}void addedge1(int u, int v){ E1[cnt].v = v, E1[cnt].nxt = head1[u], head1[u] = cnt++;}void addedge2(int u, int v){ E2[cnt].v = v, E2[cnt].nxt = head2[u], head2[u] = cnt++;}void tarjan(int x){ int now = 0; dfn[x] = low[x] = ++dfs_clock; s[++top] = x; inq[x] = 1; for(int i = head1[x]; ~i; i = E1[i].nxt){ int to = E1[i].v; if(!dfn[to]){ tarjan(to); low[x] = min(low[x], low[to]); } else if(inq[to]){ low[x] = min(low[x], dfn[to]); } } if(low[x] == dfn[x]){ scc++; while(now != x){ now = s[top]; top--; belong[now] = scc; v[scc] += c[now]; inq[now] = 0; } }}void rebuild(){ init2(); for(int i = 1; i <= n; i++){ for(int j = head1[i]; ~j; j = E1[j].nxt){ int to = E1[j].v; if(belong[i] != belong[to]){ addedge2(belong[i], belong[to]); } } }}void spfa(){ queue <int> que; que.push(belong[S]); vis[belong[S]] = 1; dp[belong[S]] = v[belong[S]]; while(!que.empty()){ int now = que.front(); que.pop(); vis[now] = 0; for(int i = head2[now]; ~i; i = E2[i].nxt){ int to = E2[i].v; if(dp[now] + v[to] > dp[to]){ dp[to] = dp[now] + v[to]; if(!vis[to]){ vis[to] = 1; que.push(to); } } } }}int main(){ init1(); scanf("%d%d", &n, &m); for(int i = 1; i <= m; i++){ int u, v; scanf("%d%d", &u, &v); addedge1(u, v); } for(int i = 1; i <= n; i++) scanf("%d", &c[i]); for(int i = 1; i <= n; i++) if(!dfn[i]) tarjan(i); scanf("%d%d", &S, &q); rebuild(); spfa(); for(int i = 1; i <= q; i++){ int x; scanf("%d", &x); if(dp[belong[x]] > ans) ans = dp[belong[x]]; } PRintf("%d/n", ans); return 0;}新闻热点
疑难解答