燃やして埋めます。後日ちゃんと詳しくまとめて解説書こうと思う。取り急ぎ。。。
問題概要
長さ の文字列 が与えられる。文字列は 'L' と 'R' で構成されている。文字列の "恐怖度" を以下のように定義する。
- 個の index ペア ui, vi (ui < vi) が与えれて、S[ui] = 'R' かつ S[vi] = 'L' なら、各 i について "恐怖度" に Bi が加算される
今、文字列の 'L' と 'R' を入れ替えることで "恐怖度" を減らすことを考える。ただし、一文字入れ替えるのには A のコストがかかる。要したコストは最終的な "恐怖度" に加算される。
最終的に得られる "恐怖度" の最小値を求めよ。
制約
考えたこと
まさに「燃やす埋める」そのもの。燃やす埋めるフレームワークでは
- 各要素 p について、p = 0 のときベースコスト Ap、p = 1 のときベースコスト Bp がかかる
- ただし多数の制約があって 1 つ 1 つの制約は
- 要素組 p, q について、p = 1 かつ q = 0 のときにコスト C が加算される
という状況を最小カットに帰着できるフレームワークになっている。今回は「L が 1」「R が 0」とを自然に対応づけることができて、制約によるコストも自然に扱える。
ベースコストは
- もともとが R のとき、L にするならコスト A、R ならコスト 0
- もともとが L のとき、L ならコスト 0、R にする ならコスト A
とすればよい。
#include <iostream> #include <vector> #include <queue> #include <algorithm> using namespace std; // edge class (for network-flow) template<class FLOWTYPE> struct Edge { int rev, from, to; FLOWTYPE cap, icap; Edge(int r, int f, int t, FLOWTYPE c) : rev(r), from(f), to(t), cap(c), icap(c) {} friend ostream& operator << (ostream& s, const Edge& E) { if (E.cap > 0) return s << E.from << "->" << E.to << '(' << E.cap << ')'; else return s; } }; // graph class (for network-flow) template<class FLOWTYPE> struct Graph { vector<vector<Edge<FLOWTYPE> > > list; Graph(int n = 0) : list(n) { } void init(int n = 0) { list.clear(); list.resize(n); } void reset() { for (int i = 0; i < (int)list.size(); ++i) for (int j = 0; j < list[i].size(); ++j) list[i][j].cap = list[i][j].icap; } inline vector<Edge<FLOWTYPE> >& operator [] (int i) { return list[i]; } inline const size_t size() const { return list.size(); } inline Edge<FLOWTYPE> &redge(Edge<FLOWTYPE> e) { if (e.from != e.to) return list[e.to][e.rev]; else return list[e.to][e.rev + 1]; } void addedge(int from, int to, FLOWTYPE cap) { list[from].push_back(Edge<FLOWTYPE>((int)list[to].size(), from, to, cap)); list[to].push_back(Edge<FLOWTYPE>((int)list[from].size() - 1, to, from, 0)); } void add_undirected_edge(int from, int to, FLOWTYPE cap) { list[from].push_back(Edge<FLOWTYPE>((int)list[to].size(), from, to, cap)); list[to].push_back(Edge<FLOWTYPE>((int)list[from].size() - 1, to, from, cap)); } }; template<class FLOWTYPE> struct Dinic { const FLOWTYPE INF = 1<<30; // to be set vector<int> level, iter; Dinic() { } void dibfs(Graph<FLOWTYPE> &G, int s) { level.assign((int)G.size(), -1); level[s] = 0; queue<int> que; que.push(s); while (!que.empty()) { int v = que.front(); que.pop(); for (int i = 0; i < G[v].size(); ++i) { Edge<FLOWTYPE> &e = G[v][i]; if (level[e.to] < 0 && e.cap > 0) { level[e.to] = level[v] + 1; que.push(e.to); } } } } FLOWTYPE didfs(Graph<FLOWTYPE> &G, int v, int t, FLOWTYPE f) { if (v == t) return f; for (int &i = iter[v]; i < G[v].size(); ++i) { Edge<FLOWTYPE> &e = G[v][i], &re = G.redge(e); if (level[v] < level[e.to] && e.cap > 0) { FLOWTYPE d = didfs(G, e.to, t, min(f, e.cap)); if (d > 0) { e.cap -= d; re.cap += d; return d; } } } return 0; } FLOWTYPE solve(Graph<FLOWTYPE> &G, int s, int t) { level.assign((int)G.size(), -1); iter.assign((int)G.size(), 0); FLOWTYPE res = 0; while (true) { dibfs(G, s); if (level[t] < 0) return res; for (int i = 0; i < (int)iter.size(); ++i) iter[i] = 0; FLOWTYPE flow = 0; while ((flow = didfs(G, s, t, INF)) > 0) { res += flow; } } } }; int main() { int N, M; string U; cin >> N >> M >> U; vector<long long> A(N); for (int i = 0; i < N; ++i) cin >> A[i]; Graph<long long> G(N+2); int s = N, t = N+1; for (int i = 0; i < N; ++i) { if (U[i] == 'R') { G.addedge(s, i, A[i]); G.addedge(i, t, 0); } else { G.addedge(s, i, 0); G.addedge(i, t, A[i]); } } for (int _ = 0; _ < M; ++_) { int a, b; long long c; cin >> a >> b >> c; --a, --b; if (a > b) swap(a, b); G.addedge(a, b, c); } Dinic<long long> din; long long res = din.solve(G, s, t); cout << res << endl; }