大意:Flymouse到达一个寝室时,可以选择进入寝室、发放礼物、倾听接收礼物或者默默的绕开这个寝室,可能会多次经过同一个寝室,但绝不会第二次进入该寝室。求:在发放礼物整个过程中,收获的最大安慰指数是多少。
思路:首先将有向图缩点,缩点后,重构图每个点内的权值为该强连通分量的权值之和(负权值赋值为0,因为可以绕过去),然后在有向无环图上找最长路径,DP、SPFA均可。
#include <iostream> #include <cstdlib> #include <cstring> #include <cstdio> #include <queue> using namespace std; const int maxn = 30010; const int maxm = 150010; const int INF = 0x3f3f3f3f; struct Edge { int v, w; int next; }edge[maxm], edge2[maxm]; int n, m; int cnt, cnt2; int scnt, top, tot; int first[maxn], low[maxn], dfn[maxn], stack[maxn], ins[maxn]; int d[maxn]; int first2[maxn]; int belong[maxn]; int cost[maxn]; int w[maxn]; void init() { cnt = cnt2 = 0; scnt = top = tot = 0; memset(first, -1, sizeof(first)); memset(first2, -1, sizeof(first2)); memset(dfn, 0, sizeof(dfn)); memset(ins, 0, sizeof(ins)); memset(cost, 0, sizeof(cost)); } void read_graph(int u, int v) { edge[cnt].v = v; edge[cnt].next = first[u], first[u] = cnt++; } void read_graph2(int u, int v) { edge2[cnt2].v = v; edge2[cnt2].next = first2[u], first2[u] = cnt2++; } void dfs(int u) { int v; dfn[u] = low[u] = ++tot; stack[top++] = u; ins[u] = 1; for(int e = first[u]; e != -1; e = edge[e].next) { v = edge[e].v; if(!dfn[v]) { dfs(v); low[u] = min(low[u], low[v]); } else if(ins[v]) { low[u] = min(low[u], dfn[v]); } } if(dfn[u] == low[u]) { scnt++; do { v = stack[--top]; belong[v] = scnt; ins[v] = 0; cost[scnt] += w[v]; }while(u != v); } } void Tarjan() { for(int v = 1; v <= n; v++) if(!dfn[v]) dfs(v); } void read_case() { init(); for(int i = 1; i <= n; i++) { scanf("%d", &w[i]); if(w[i] < 0) w[i] = 0; } while(m--) { int u, v, w; scanf("%d%d", &u, &v); u++; v++; read_graph(u, v); } } void build() { for(int u = 1; u <= n; u++) { for(int e = first[u]; e != -1; e = edge[e].next) { int v = edge[e].v, w = edge[e].w; if(belong[u] != belong[v]) { read_graph2(belong[u], belong[v]); } } } } bool vis[maxn]; int dp(int u) { int &ans = d[u]; if(vis[u]) return ans; ans = cost[u]; for(int e = first2[u]; e != -1; e = edge2[e].next) { int v = edge2[e].v; ans = max(ans, dp(v) + cost[u]); } return ans; } int cal() { memset(vis, 0, sizeof(vis)); memset(d, 0, sizeof(d)); int ans = 0; for(int i = 1; i <= scnt; i++) ans = max(ans, dp(i)); return ans; } void solve() { read_case(); Tarjan(); build(); int ans = cal(); printf("%d\n", ans); } int main() { while(~scanf("%d%d", &n, &m)) { solve(); } return 0; }