AOJ 2293 - Dangerous Tower
http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=2293
解法
2011/Practice/夏合宿/講評 - ACM-ICPC Japanese Alumni Group を参照.
解説スライドにあるように,横の長さが異なるように積み木を選べばそれらをすべて使える点に注目して最小費用流の問題に落とす.
積み木 i の使い方は
- A[i] を横にして +B[i]
- B[i] を横にして +A[i]
- 使わずに +0
の3つ.これらを
- A[i] のノードへコスト -B[i] のエッジ
- B[i] のノードへコスト -A[i] のエッジ
- ダミーノードへコスト 0 のエッジ
で表す.
同じ横の長さは1つまでしか使えないことを,横の長さのノードからシンクへの容量1のエッジで表す. ダミーノードからシンクへのエッジの容量は無限大.
aoj/2293.cc1 #include <cstdio> 2 #include <vector> 3 #include <queue> 4 #include <algorithm> 5 #include <limits> 6 using namespace std; 7 static const int MAXN = 3010; 8 9 template <class Flow, class Cost> 10 struct node 11 { 12 int index; 13 Flow capacity; 14 Cost cost; 15 node(int i, Flow c, Cost d) : index(i), capacity(c), cost(d) {} 16 }; 17 18 template <class Flow, class Cost> 19 node<Flow, Cost> make_node(int i, Flow c, Cost d) { return node<Flow, Cost>(i, c, d); } 20 21 template <class Flow, class Cost> 22 pair<Flow, Cost> 23 primal_dual(const vector<node<Flow, Cost> > *g, int N, int source, int sink)/*{{{*/ 24 { 25 static Flow capacity[MAXN][MAXN], flow[MAXN][MAXN]; 26 static Cost cost[MAXN][MAXN]; 27 for (int i = 0; i < N; i++) { 28 for (typename vector<node<Flow, Cost> >::const_iterator it(g[i].begin()); it != g[i].end(); ++it) { 29 capacity[i][it->index] += it->capacity; 30 cost[i][it->index] += it->cost; 31 } 32 } 33 pair<Flow, Cost> total; 34 static Cost h[MAXN], dist[MAXN]; 35 static int parent[MAXN]; 36 for (Flow f = numeric_limits<Flow>::max(); f > 0; ) { 37 fill_n(dist, N, 1000000); 38 dist[source] = 0; 39 fill_n(parent, N, -1); 40 priority_queue<pair<Cost,int> > q; 41 q.push(make_pair(0, source)); 42 while (!q.empty()) { 43 const int n = q.top().second; 44 const Cost c = -q.top().first; 45 q.pop(); 46 if (dist[n] < c) { 47 continue; 48 } 49 for (typename vector<node<Flow, Cost> >::const_iterator it = g[n].begin(); it != g[n].end(); ++it) { 50 if (capacity[n][it->index] - flow[n][it->index] > 0) { 51 const Cost c2 = c + cost[n][it->index] + h[n] - h[it->index]; 52 if (c2 < dist[it->index]) { 53 dist[it->index] = c2; 54 parent[it->index] = n; 55 q.push(make_pair(-c2, it->index)); 56 } 57 } 58 } 59 } 60 if (parent[sink] == -1) { 61 break; 62 } 63 64 Flow e = f; 65 for (int i = sink; i != source; i = parent[i]) { 66 e = min(e, capacity[parent[i]][i] - flow[parent[i]][i]); 67 } 68 for (int i = sink; i != source; i = parent[i]) { 69 total.second += e * cost[parent[i]][i]; 70 flow[i][parent[i]] -= e; 71 flow[parent[i]][i] += e; 72 } 73 f -= e; 74 total.first += e; 75 for (int i = 0; i < N; i++) { 76 h[i] += dist[i]; 77 } 78 } 79 80 return total; 81 }/*}}}*/ 82 83 int main() 84 { 85 int N; 86 scanf("%d", &N); 87 static pair<int,int> blocks[1000]; 88 vector<int> v; 89 for (int i = 0; i < N; i++) { 90 scanf("%d %d", &blocks[i].first, &blocks[i].second); 91 v.push_back(blocks[i].first); 92 v.push_back(blocks[i].second); 93 } 94 sort(v.begin(), v.end()); 95 96 static vector<node<int, long long> > g[MAXN]; 97 const int source = N + v.size(); 98 const int sink = source + 1; 99 const int dummy = sink + 1; 100 for (int i = 0; i < N; i++) { 101 const long long a = blocks[i].first, b = blocks[i].second; 102 const int j = lower_bound(v.begin(), v.end(), a) - v.begin(); 103 const int k = lower_bound(v.begin(), v.end(), b) - v.begin(); 104 g[source].push_back(make_node(i, 1, 0LL)); 105 g[i].push_back(make_node(source, 0, 0LL)); 106 107 g[i].push_back(make_node(dummy, 1, 0LL)); 108 g[dummy].push_back(make_node(i, 0, 0LL)); 109 110 g[i].push_back(make_node(N+j, 1, -b)); 111 g[N+j].push_back(make_node(i, 0, b)); 112 if (b != a) { 113 g[i].push_back(make_node(N+k, 1, -a)); 114 g[N+k].push_back(make_node(i, 0, a)); 115 } 116 } 117 for (vector<int>::size_type i = 0; i < v.size(); i++) { 118 g[N+i].push_back(make_node(sink, 1, 0LL)); 119 g[sink].push_back(make_node(N+i, 0, 0LL)); 120 } 121 g[dummy].push_back(make_node(sink, N, 0LL)); 122 123 printf("%lld\n", -primal_dual(g, dummy+1, source, sink).second); 124 return 0; 125 }