最大の次数が3なので、ある頂点に関して状態を2ビットで表せる。
DP[4^20]
int m_dist(int x1, int y1, int x2, int y2) { return abs(x1 - x2) + abs(y1 - y2); } inline int mask(int node, int bit) { node *= 2; return bit & (3 * (1 << node)); } inline int degree(int node, int bit) { bit = mask(node, bit); return bit >> (node * 2); } inline int add_edge(int a, int b, int bit) { int da = degree(a, bit) + 1; int db = degree(b, bit) + 1; bit -= mask(a, bit); bit -= mask(b, bit); return bit + (da * (1 << (a * 2))) + (db * (1 << (b * 2))); } const int N = 10 + 1; int g[N][N]; const int M = 1 << 21; int dp[2][M]; class TwinTowns { public: vector <int> optimalTwinTowns(vector <int> x, vector <int> y, int maxPartners, int minDistance) { const int size = x.size(); for (int i = 0; i < size; ++i) { for (int j = 0; j < size; ++j) { g[i][j] = m_dist(x[i], y[i], x[j], y[j]); } } const int inf = 1 << 30; fill(&dp[0][0], &dp[2 - 1][M - 1] + 1, inf); dp[0][0] = 0; const int BIT = 1 << (size * 2); int next = 0, curr = 0; for (int i = 0; i < size; ++i) { for (int j = i + 1; j < size; ++j) { curr = next; next = (curr + 1) % 2; copy(&dp[curr][0], &dp[curr][M - 1], &dp[next][0]); for (int bit = 0; bit < BIT; ++bit) { if (inf <= dp[curr][bit]) continue; if (g[i][j] < minDistance) continue; if (maxPartners <= degree(i, bit)) continue; if (maxPartners <= degree(j, bit)) continue; int b = add_edge(i, j, bit); dp[next][b] = min(dp[next][b], dp[curr][bit] + g[i][j]); } } } int edge = 0; int cost = inf; for (int bit = 0; bit < BIT; ++bit) { if (dp[next][bit] == inf) continue; int sum = 0; for (int i = 0; i < size; ++i) { sum += degree(i, bit); } int deg = sum / 2; if (edge < deg) { edge = deg; cost = dp[next][bit]; } else if (edge == deg) { cost = min(cost, dp[next][bit]); } } vector<int> ret(2, 0); ret[0] = edge; ret[1] = cost; return ret; } };