結果
| 問題 |
No.3201 Corporate Synergy
|
| コンテスト | |
| ユーザー |
srjywrdnprkt
|
| 提出日時 | 2025-07-25 15:51:52 |
| 言語 | C++23 (gcc 13.3.0 + boost 1.87.0) |
| 結果 |
AC
|
| 実行時間 | 3 ms / 2,000 ms |
| コード長 | 4,693 bytes |
| コンパイル時間 | 4,078 ms |
| コンパイル使用メモリ | 297,668 KB |
| 実行使用メモリ | 7,716 KB |
| 最終ジャッジ日時 | 2025-07-25 15:51:57 |
| 合計ジャッジ時間 | 4,512 ms |
|
ジャッジサーバーID (参考情報) |
judge3 / judge5 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 2 |
| other | AC * 20 |
ソースコード
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
struct edge{
int to; ll cap; int rev;
};
//Dinic(0-indexed)
struct MaxFlow{
private:
static const ll INF=9e18;
vector<int> dist, iter;
vector<pair<int, int>> idx;
void bfs(int s){
int from;
fill(dist.begin(), dist.end(), -1);
queue<int> que;
que.push(s);
dist[s] = 0;
while(!que.empty()){
from = que.front(); que.pop();
for (auto &e : E[from]){
if (e.cap > 0 && dist[e.to] == -1){
dist[e.to] = dist[from] + 1;
que.push(e.to);
}
}
}
}
ll dfs(int s, int t, ll flow){
if (s == t) return flow;
for (int &i=iter[s]; i<E[s].size(); i++){
edge &e = E[s][i];
if (e.cap <= 0 || dist[s] >= dist[e.to]) continue;
ll d = dfs(e.to, t, min(flow, e.cap));
if (d > 0){
e.cap -= d;
E[e.to][e.rev].cap += d;
return d;
}
}
return 0;
}
public:
int N, M=0;
vector<vector<edge>> E;
MaxFlow(int n) : N(n) {
E.resize(N);
dist.resize(N);
iter.resize(N);
}
void add_edge(int from, int to, ll cap){
M++;
idx.push_back({from, (int)E[from].size()});
E[from].push_back({to, cap, (int)E[to].size()});
E[to].push_back({from, 0, (int)E[from].size()-1});
}
ll solve(int s, int t, ll limit=INF){
ll res = 0, flow;
while(1){
bfs(s);
if (dist[t] == -1) break;
for (int i=0; i<N; i++) iter[i] = 0;
while((flow = dfs(s, t, INF)) > 0){
res += flow;
if (res >= limit) return limit;
}
}
return res;
}
//i番目の辺の(from, to, flow)を求める。
tuple<int, int, ll> get_flow(int i){
assert (i < M);
edge &e = E[idx[i].first][idx[i].second];
return {idx[i].first, e.to, E[e.to][e.rev].cap};
}
//最小カット(s->t)を求める
vector<tuple<int, int, ll>> get_cut(int s){
vector<bool> vst(N);
vector<tuple<int, int, ll>> res;
auto dfs=[&](auto self, int from)->void{
vst[from] = 1;
for (auto &e : E[from]){
if (vst[e.to]) continue;
if (e.cap) self(self, e.to);
}
};
dfs(dfs, s);
for (int i=0; i<M; i++){
edge &e = E[idx[i].first][idx[i].second];
if (vst[idx[i].first] && !vst[e.to]) res.push_back({idx[i].first, e.to, E[e.to][e.rev].cap});
}
return res;
}
};
int main(){
cin.tie(nullptr);
ios_base::sync_with_stdio(false);
/*
燃やす埋める
事業をする(source)かしない(sink)か
最大利益=損失を最小化する。(minimum cut)
(1)
P_i>=0ならsource->iにP_iの損失を張る。(sinkにするとP_i損)
P_i<0ならi->sinkにP_iの損失を張る。(sourceにするとP_i損)
(2)
V->Uに無限の損失を張る。
Vを選ぶならUも選ばないといけないから
(3)
source->z(A-B対)にSの損失を張る。
source->zを切らない場合A-B対は切ってはいけないのでz->A, z->Bに無限の損失を張る。
*/
ll N, M, K, ans=0;
cin >> N;
vector<ll> P(N);
for (int i=0; i<N; i++) cin >> P[i];
cin >> M;
vector<ll> U(M), V(M);
for (int i=0; i<M; i++) cin >> U[i] >> V[i];
cin >> K;
vector<ll> A(K), B(K), S(K);
for (int i=0; i<K; i++) cin >> A[i] >> B[i] >> S[i];
MaxFlow mf(N+K+2);
for (int i=0; i<N; i++){
if (P[i] > 0){
mf.add_edge(0, i+1, P[i]);
mf.add_edge(i+1, N+K+1, 0);
ans += P[i];
}
else{
mf.add_edge(0, i+1, 0);
mf.add_edge(i+1, N+K+1, -P[i]);
}
}
for (int i=0; i<M; i++) mf.add_edge(V[i], U[i], 1e18);
for (int i=0; i<K; i++){
ans += S[i];
mf.add_edge(0, i+N+1, S[i]);
mf.add_edge(i+N+1, A[i], 1e18);
mf.add_edge(i+N+1, B[i], 1e18);
}
cout << ans-mf.solve(0, N+K+1) << endl;
return 0;
}
srjywrdnprkt