結果
| 問題 |
No.3201 Corporate Synergy
|
| コンテスト | |
| ユーザー |
|
| 提出日時 | 2025-07-03 08:47:32 |
| 言語 | C++23 (gcc 13.3.0 + boost 1.87.0) |
| 結果 |
RE
|
| 実行時間 | - |
| コード長 | 3,967 bytes |
| コンパイル時間 | 1,258 ms |
| コンパイル使用メモリ | 121,128 KB |
| 実行使用メモリ | 814,484 KB |
| 最終ジャッジ日時 | 2025-07-06 10:24:49 |
| 合計ジャッジ時間 | 3,883 ms |
|
ジャッジサーバーID (参考情報) |
judge2 / judge5 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | RE * 2 |
| other | RE * 4 MLE * 1 -- * 15 |
ソースコード
#include <iostream>
#include <vector>
#include <numeric>
// AtCoder Libraryからmaxflowをインクルード
#include <atcoder/maxflow>
using namespace std;
int main() {
// 高速な入出力
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int N, M, K;
cin >> N >> M >> K;
vector<long long> P(N);
for (int i = 0; i < N; ++i) {
cin >> P[i];
}
vector<pair<int, int>> 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<tuple<int, int, long long>> 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<long long> 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;
}