Div2 500 - SquaresCovering
問題
与えられた座標を覆うように正方形を配置する.正方形それぞれにコストがかかるので,その総和の最小値はいくらになるか?
考え方
点の数が高々 16 個なので,どの点がまだカバーされてないかをビットで表した DP で大丈夫だと思う.点を x 座標なりで適宜ソートしておくと計算しやすい.正方形の位置については,適当に移動させれば覆う点自体は変わらずに左辺と上辺に点があるように変更できるので,そういう場合だけ考慮すればいい.
コード
#include <vector> #include <algorithm> #include <set> using namespace std; typedef pair<int, int> Queue; // cost, remained square typedef pair<int, int> Point; // x, y const int INF = 0x7fffffff; class SquaresCovering { set<Queue> q; vector<Point> point; vector<int> pay; void push(int rem, int cost) { if( pay[rem] > cost ) { pay[rem] = cost; q.insert(Queue(cost, rem)); } } public: int minCost(vector<int> x, vector<int> y, vector<int> cost, vector<int> sides) { const int Ns = cost.size(); // # of square const int Np = x.size(); // # of points const int Nf = 1 << Np; // # of flag pattern for( int i = 0 ; i < Np ; ++i ) point.push_back(Point(x[i], y[i])); sort(point.begin(), point.end()); pay.resize(Nf, INF); q.insert(Queue(0, Nf - 1)); pay[Nf - 1] = 0; while( !q.empty() ) { int cst = q.begin()->first, flg = q.begin()->second, id; if( flg == 0 ) break; q.erase(q.begin()); // Check left-most point for( id = 0 ; id < Np ; ++id ) if( (1 << id) & flg ) break; for( int i = 0 ; i < Ns ; ++i ) { // Square selection int size = sides[i], ncost = cst + cost[i]; int right = point[id].first + size; for( int j = id ; j < Np ; ++j ) { // To detect top position if( (flg & (1 << j)) == 0 ) continue; if( right < point[j].first ) continue; if( point[j].second < point[id].second || point[id].second + size < point[j].second ) continue; const int top = point[j].second, bottom = top - size; int rem = flg; for( int k = id ; k < Np ; ++k ) { // Check each point is in square if( (rem & (1 << k)) == 0 ) continue; if( right < point[k].first ) continue; if( bottom <= point[k].second && point[k].second <= top ) rem ^= (1 << k); } push(rem, ncost); } } } return pay[0]; } };