#include #include #include // AtCoder Libraryからmaxflowをインクルード #include using namespace std; int main() { // 高速な入出力 ios_base::sync_with_stdio(false); cin.tie(NULL); int N, M, K; cin >> N >> M >> K; vector P(N); for (int i = 0; i < N; ++i) { cin >> P[i]; } vector> dependencies(M); for (int i = 0; i < M; ++i) { cin >> dependencies[i].first >> dependencies[i].second; // 1-basedから0-basedへ変換 dependencies[i].first--; dependencies[i].second--; } vector> synergies(K); for (int i = 0; i < K; ++i) { cin >> get<0>(synergies[i]) >> get<1>(synergies[i]) >> get<2>(synergies[i]); // 1-basedから0-basedへ変換 get<0>(synergies[i])--; get<1>(synergies[i])--; } // --- 最小カット問題のグラフ構築 --- // ノードの割り当て // 0..N-1: 都市ノード // N..N+K-1: 事業提携の補助ノード // N+K: ソースS // N+K+1: シンクT int S = N + K; int T = N + K + 1; atcoder::mf_graph mf(N + K + 2); // 事実上の無限大容量 const long long INF = 1e18; // 潜在的な利益の合計 long long total_potential_profit = 0; // 1. 単独事業の利益/損失をモデル化 for (int i = 0; i < N; ++i) { if (P[i] > 0) { // 正の利益: Sから都市ノードへの辺 // この利益は得られる可能性がある total_potential_profit += P[i]; mf.add_edge(S, i, P[i]); } else { // 負の利益 (損失): 都市ノードからTへの辺 // このコストは発生する可能性がある mf.add_edge(i, T, -P[i]); } } // 2. 生産フロー (依存関係) をモデル化 // U -> V (Vの事業にはUが必要) for (const auto& dep : dependencies) { int u = dep.first; int v = dep.second; // V を選ぶ(S側)ならUも選ばなければならない(S側) // V(S側) -> U(T側) というカットを禁止する mf.add_edge(v, u, INF); } // 3. 事業提携 (シナジー/ディスシナジー) をモデル化 for (int j = 0; j < K; ++j) { int a = get<0>(synergies[j]); int b = get<1>(synergies[j]); long long s_val = get<2>(synergies[j]); int syn_node = N + j; if (s_val > 0) { // シナジー利益 // この利益を得るためにはAとBの両方が必要 total_potential_profit += s_val; // Sからシナジーノードへ、利益分の容量を持つ辺 mf.add_edge(S, syn_node, s_val); // シナジーノードを選ぶなら、AとBも選ばなければならない mf.add_edge(syn_node, a, INF); mf.add_edge(syn_node, b, INF); } else { // ディスシナジー損失 // AとBの両方を行うと、このコストが発生する long long cost = -s_val; // シナジーノードからTへ、コスト分の容量を持つ辺 mf.add_edge(syn_node, T, cost); // AとBの両方を選ぶなら、シナジーノード(コスト)も受け入れなければならない mf.add_edge(a, syn_node, INF); mf.add_edge(b, syn_node, INF); } } // --- 計算と結果の出力 --- // SからTへの最大フローを計算 (これが最小カットのコストに等しい) long long min_cut_cost = mf.flow(S, T); // 最大利益 = (潜在的な利益の合計) - (最小カットコスト) long long max_profit = total_potential_profit - min_cut_cost; cout << max_profit << endl; return 0; }