Submission #63893180
Source Code Expand
/*
[解法の説明]
1. 基本的な方針
- 社員 i にちょうど T[i] 回掃除当番が回ってくると仮定する
- このとき、社員 a[i], b[i] に T[i]/2 回掃除当番が渡る、と考えらえる
- したがって、(a[j], b[j] = i となるものに対する T[j]/2 の合計) ができるだけ T[i] に近くなれば良い
- この "誤差" をできるだけ小さくする a[i], b[i] を決めることを考える
2. "ビンパッキング問題" のような問題としてとらえる
- 結局 1. で述べた問題は以下の問題になる
- N 個のビンがあって、それぞれ容量 T[0], T[1], ..., T[N-1] である
- アイテムが 2N 個あって、それぞれサイズ T[0]/2, T[0]/2, T[1]/2, T[1]/2, ..., T[N-1]/2, T[N-1]/2 である
- すべてのアイテムをビンに入れるとき、各ビンの |容量 - 入れたアイテムのサイズの合計| の総和を最小化する
- これだと、ビン i にサイズ T[i]/2, T[i]/2 のアイテムを入れるのが最適になる
- しかし、この解では社員 0 がずっと掃除当番をやることになってしまう
- そのため、ビン i にはサイズ T[i]/2 のアイテムを入れてはいけない、という制約を入れた問題を解くことにする
3. 山登り法で最適化する
- 適当な初期解から始める
- 以下の状態遷移を行って解の改善を試みる
- 2 つのビンを選び、その中のアイテムを組み替える、という変更を行う
- 誤差がより小さくなったら、変更を採用する
- 改善できなくなる or 実行時間制限を過ぎる まで改善を繰り返す
- 各ビンには平均 2 個程度しかアイテムがないので、組み替えの方法は全探索できる
- 平均計算量 O(1) で改善できるかが判定でき、スコアを平均計算量 O(1) で差分更新できる
4. 山登り法の工夫
- 焼きなまし法をするとできるが、ここでは別のアプローチを考える
- 反復局所探索法のアプローチ
[1] 2 つのビンの組を全探索して、その中で改善できるものを探す
[2] N(N-1)/2 通りのどれでも誤差が改善しなかったら (局所解)、以下の kick 操作を行う
- アイテムを 1 つランダムに選んで、それを別のビンに移し替える
[3] 局所解に到達するたびに実際のスコアを計算する
- 時には誤差と比べて実際のスコアが低くなることがあるが、これは手順 [3] で実際のスコアを何回も計算するので対処できる
- 手順 [1] から [3] までのループは、実行時間制限 2 秒では 100 回程度回る
- 単純な誤差ではなく、2 乗誤差を最小化する
*/
#include <bits/stdc++.h>
using namespace std;
const int INF = 1012345678;
namespace myrandom {
uint64_t seed = 1234567891234567891;
uint64_t xorshift64() {
seed ^= seed << 13;
seed ^= seed >> 7;
seed ^= seed << 17;
return seed;
}
// l 以上 r 未満のランダムな整数を返す関数
int64_t next_int(int64_t l, int64_t r) {
int64_t z = xorshift64() % (r - l);
return l + z;
}
};
// 社員を表す構造体: a[i], b[i] を表す
class person {
public:
int a, b;
person() : a(-1), b(-1) {}
person(int a_, int b_) : a(a_), b(b_) {}
};
// 求めた答えのスコアを計算する関数
int get_score(int N, int L, const vector<int>& T, const vector<person>& plan) {
vector<int> count(N, 0);
int cur = 0;
for (int i = 0; i < L; i++) {
if (count[cur] % 2 == 0) {
cur = plan[cur].a;
} else {
cur = plan[cur].b;
}
count[cur] += 1;
}
int score = 2 * L;
for (int i = 0; i < N; i++) {
score -= abs(count[i] - T[i]);
}
return score;
}
vector<person> solver(int N, int L, const vector<int> T) {
// step #1. ビンに入れるアイテムの大きさを計算
vector<int> X(N * 2);
for (int i = 0; i < N; i++) {
X[i * 2 + 0] = (T[i] + 1) / 2;
X[i * 2 + 1] = (T[i] + 0) / 2;
}
// step #2. 山登り法の準備
const int CAPACITY = 5;
vector<int> G(N * 2);
vector<int> C(N);
vector<int> S(N);
vector<array<int, CAPACITY> > GL(N);
for (int i = 0; i < N; i++) {
fill(GL[i].begin(), GL[i].end(), -1);
}
for (int i = 0; i < N * 2; i++) {
do {
G[i] = myrandom::next_int(0, N);
} while (G[i] == i / 2 || C[G[i]] == CAPACITY);
S[G[i]] += X[i];
GL[G[i]][C[G[i]]++] = i;
}
// step #3. ビン a, b を組み替えて改善できるかを全探索で判定する関数
auto mixing = [&](int a, int b) -> bool {
vector<int> V;
V.reserve(C[a] + C[b]);
int base_ca = 0, base_sa = 0;
for (int i = 0; i < C[a]; i++) {
if (GL[a][i] / 2 == b) {
base_ca++;
base_sa += X[GL[a][i]];
} else {
V.push_back(GL[a][i]);
}
}
int base_cb = 0, base_sb = 0;
for (int i = 0; i < C[b]; i++) {
if (GL[b][i] / 2 == a) {
base_cb++;
base_sb += X[GL[b][i]];
} else {
V.push_back(GL[b][i]);
}
}
int VS = V.size();
vector<int> P(1 << VS);
for (int i = 0; i < VS; i++) {
for (int j = 0; j < (1 << i); j++) {
P[j | (1 << i)] = P[j] + X[V[i]];
}
}
int total = P[(1 << VS) - 1];
pair<int, int> opt = {(S[a] - T[a]) * (S[a] - T[a]) + (S[b] - T[b]) * (S[b] - T[b]), -1};
for (int i = 0; i < (1 << VS); i++) {
int ca = base_ca + __builtin_popcount(i);
int cb = base_cb + (VS - __builtin_popcount(i));
if (ca <= CAPACITY && cb <= CAPACITY) {
int sa = base_sa + P[i];
int sb = base_sb + (total - P[i]);
int loss = (sa - T[a]) * (sa - T[a]) + (sb - T[b]) * (sb - T[b]);
opt = min(opt, {loss, i});
}
}
if (opt.second == -1) {
return false;
}
array<int, CAPACITY> gla, glb;
fill(gla.begin(), gla.end(), -1);
fill(glb.begin(), glb.end(), -1);
int nca = 0;
for (int i = 0; i < C[a]; i++) {
if (GL[a][i] / 2 == b) {
gla[nca++] = GL[a][i];
}
}
int ncb = 0;
for (int i = 0; i < C[b]; i++) {
if (GL[b][i] / 2 == a) {
glb[ncb++] = GL[b][i];
}
}
for (int i = 0; i < VS; i++) {
if ((opt.second >> i) & 1) {
gla[nca++] = V[i];
G[V[i]] = a;
} else {
glb[ncb++] = V[i];
G[V[i]] = b;
}
}
C[a] = nca;
C[b] = ncb;
GL[a] = gla;
GL[b] = glb;
S[a] = 0;
for (int i = 0; i < nca; i++) {
S[a] += X[gla[i]];
}
S[b] = 0;
for (int i = 0; i < ncb; i++) {
S[b] += X[glb[i]];
}
return true;
};
// step #4. 2 つのビンの組を全探索して、改善できるかを判定する関数
auto find_improvement = [&]() -> bool {
for (int i = 0; i < N; i++) {
for (int j = i + 1; j < N; j++) {
if (abs(S[i] - T[i]) + abs(S[j] - T[j]) >= 2 && mixing(i, j)) {
return true;
}
}
}
return false;
};
// step #5. 山登り法のメイン部分
const double TIME_LIMIT = 1.9;
time_t start_clock = clock();
double time_ratio = 0.0;
int best_score = -INF;
vector<person> best_ans;
int64_t loops = 0;
while (true) {
time_t cur_clock = clock();
time_ratio = (cur_clock - start_clock) / (TIME_LIMIT * CLOCKS_PER_SEC);
if (time_ratio >= 1.0) {
break;
}
loops++;
int64_t subloops = 0;
while (find_improvement()) {
subloops++;
}
int loss = 0;
for (int i = 0; i < N; i++) {
loss += abs(S[i] - T[i]);
}
vector<person> ans(N);
for (int i = 0; i < N; i++) {
ans[i] = person(G[i * 2 + 0], G[i * 2 + 1]);
}
int score = get_score(N, L, T, ans);
cerr << "loop #" << loops << ": loss = " << loss << ", score = " << score << endl;
if (best_score < score) {
best_score = score;
best_ans = ans;
}
int a = myrandom::next_int(0, 2 * N);
int b;
do {
b = myrandom::next_int(0, N);
} while (b == G[a] || b == a / 2 || C[b] == CAPACITY);
for (int i = 0; i < C[G[a]] - 1; i++) {
if (GL[G[a]][i] == a) {
GL[G[a]][i] = GL[G[a]][C[G[a]] - 1];
GL[G[a]][C[G[a]] - 1] = -1;
break;
}
}
C[G[a]]--;
S[G[a]] -= X[a];
G[a] = b;
GL[b][C[b]] = a;
C[b]++;
S[b] += X[a];
}
// 求めた答えを返す
return best_ans;
}
int main() {
// 入力
int N, L;
cin >> N >> L;
vector<int> T(N);
for (int i = 0; i < N; i++) {
cin >> T[i];
}
// 答えを求める
vector<person> ans = solver(N, L, T);
// 出力
for (int i = 0; i < N; i++) {
cout << ans[i].a << ' ' << ans[i].b << endl;
}
return 0;
}
Submission Info
| Submission Time | |
|---|---|
| Task | A - Cleaning Up |
| User | square1001 |
| Language | C++ 20 (gcc 12.2) |
| Score | 149870096 |
| Code Size | 8603 Byte |
| Status | AC |
| Exec Time | 1956 ms |
| Memory | 3768 KiB |
Judge Result
| Set Name | test_ALL | ||
|---|---|---|---|
| Score / Max Score | 149870096 / 150000000 | ||
| Status |
|
| Set Name | Test Cases |
|---|---|
| test_ALL | test_0000.txt, test_0001.txt, test_0002.txt, test_0003.txt, test_0004.txt, test_0005.txt, test_0006.txt, test_0007.txt, test_0008.txt, test_0009.txt, test_0010.txt, test_0011.txt, test_0012.txt, test_0013.txt, test_0014.txt, test_0015.txt, test_0016.txt, test_0017.txt, test_0018.txt, test_0019.txt, test_0020.txt, test_0021.txt, test_0022.txt, test_0023.txt, test_0024.txt, test_0025.txt, test_0026.txt, test_0027.txt, test_0028.txt, test_0029.txt, test_0030.txt, test_0031.txt, test_0032.txt, test_0033.txt, test_0034.txt, test_0035.txt, test_0036.txt, test_0037.txt, test_0038.txt, test_0039.txt, test_0040.txt, test_0041.txt, test_0042.txt, test_0043.txt, test_0044.txt, test_0045.txt, test_0046.txt, test_0047.txt, test_0048.txt, test_0049.txt, test_0050.txt, test_0051.txt, test_0052.txt, test_0053.txt, test_0054.txt, test_0055.txt, test_0056.txt, test_0057.txt, test_0058.txt, test_0059.txt, test_0060.txt, test_0061.txt, test_0062.txt, test_0063.txt, test_0064.txt, test_0065.txt, test_0066.txt, test_0067.txt, test_0068.txt, test_0069.txt, test_0070.txt, test_0071.txt, test_0072.txt, test_0073.txt, test_0074.txt, test_0075.txt, test_0076.txt, test_0077.txt, test_0078.txt, test_0079.txt, test_0080.txt, test_0081.txt, test_0082.txt, test_0083.txt, test_0084.txt, test_0085.txt, test_0086.txt, test_0087.txt, test_0088.txt, test_0089.txt, test_0090.txt, test_0091.txt, test_0092.txt, test_0093.txt, test_0094.txt, test_0095.txt, test_0096.txt, test_0097.txt, test_0098.txt, test_0099.txt, test_0100.txt, test_0101.txt, test_0102.txt, test_0103.txt, test_0104.txt, test_0105.txt, test_0106.txt, test_0107.txt, test_0108.txt, test_0109.txt, test_0110.txt, test_0111.txt, test_0112.txt, test_0113.txt, test_0114.txt, test_0115.txt, test_0116.txt, test_0117.txt, test_0118.txt, test_0119.txt, test_0120.txt, test_0121.txt, test_0122.txt, test_0123.txt, test_0124.txt, test_0125.txt, test_0126.txt, test_0127.txt, test_0128.txt, test_0129.txt, test_0130.txt, test_0131.txt, test_0132.txt, test_0133.txt, test_0134.txt, test_0135.txt, test_0136.txt, test_0137.txt, test_0138.txt, test_0139.txt, test_0140.txt, test_0141.txt, test_0142.txt, test_0143.txt, test_0144.txt, test_0145.txt, test_0146.txt, test_0147.txt, test_0148.txt, test_0149.txt |
| Case Name | Status | Exec Time | Memory |
|---|---|---|---|
| test_0000.txt | AC | 1914 ms | 3620 KiB |
| test_0001.txt | AC | 1914 ms | 3612 KiB |
| test_0002.txt | AC | 1916 ms | 3488 KiB |
| test_0003.txt | AC | 1916 ms | 3764 KiB |
| test_0004.txt | AC | 1912 ms | 3584 KiB |
| test_0005.txt | AC | 1910 ms | 3572 KiB |
| test_0006.txt | AC | 1921 ms | 3616 KiB |
| test_0007.txt | AC | 1917 ms | 3528 KiB |
| test_0008.txt | AC | 1903 ms | 3528 KiB |
| test_0009.txt | AC | 1921 ms | 3528 KiB |
| test_0010.txt | AC | 1909 ms | 3764 KiB |
| test_0011.txt | AC | 1910 ms | 3488 KiB |
| test_0012.txt | AC | 1911 ms | 3668 KiB |
| test_0013.txt | AC | 1931 ms | 3528 KiB |
| test_0014.txt | AC | 1923 ms | 3596 KiB |
| test_0015.txt | AC | 1919 ms | 3640 KiB |
| test_0016.txt | AC | 1908 ms | 3588 KiB |
| test_0017.txt | AC | 1908 ms | 3484 KiB |
| test_0018.txt | AC | 1912 ms | 3596 KiB |
| test_0019.txt | AC | 1908 ms | 3608 KiB |
| test_0020.txt | AC | 1920 ms | 3632 KiB |
| test_0021.txt | AC | 1956 ms | 3580 KiB |
| test_0022.txt | AC | 1914 ms | 3604 KiB |
| test_0023.txt | AC | 1922 ms | 3528 KiB |
| test_0024.txt | AC | 1921 ms | 3636 KiB |
| test_0025.txt | AC | 1918 ms | 3624 KiB |
| test_0026.txt | AC | 1917 ms | 3524 KiB |
| test_0027.txt | AC | 1916 ms | 3560 KiB |
| test_0028.txt | AC | 1908 ms | 3576 KiB |
| test_0029.txt | AC | 1914 ms | 3584 KiB |
| test_0030.txt | AC | 1906 ms | 3528 KiB |
| test_0031.txt | AC | 1911 ms | 3760 KiB |
| test_0032.txt | AC | 1907 ms | 3628 KiB |
| test_0033.txt | AC | 1902 ms | 3616 KiB |
| test_0034.txt | AC | 1917 ms | 3640 KiB |
| test_0035.txt | AC | 1909 ms | 3488 KiB |
| test_0036.txt | AC | 1932 ms | 3528 KiB |
| test_0037.txt | AC | 1910 ms | 3644 KiB |
| test_0038.txt | AC | 1913 ms | 3648 KiB |
| test_0039.txt | AC | 1910 ms | 3560 KiB |
| test_0040.txt | AC | 1915 ms | 3628 KiB |
| test_0041.txt | AC | 1919 ms | 3636 KiB |
| test_0042.txt | AC | 1909 ms | 3672 KiB |
| test_0043.txt | AC | 1916 ms | 3596 KiB |
| test_0044.txt | AC | 1904 ms | 3488 KiB |
| test_0045.txt | AC | 1941 ms | 3488 KiB |
| test_0046.txt | AC | 1915 ms | 3616 KiB |
| test_0047.txt | AC | 1916 ms | 3588 KiB |
| test_0048.txt | AC | 1920 ms | 3580 KiB |
| test_0049.txt | AC | 1908 ms | 3632 KiB |
| test_0050.txt | AC | 1911 ms | 3608 KiB |
| test_0051.txt | AC | 1915 ms | 3524 KiB |
| test_0052.txt | AC | 1910 ms | 3620 KiB |
| test_0053.txt | AC | 1904 ms | 3628 KiB |
| test_0054.txt | AC | 1915 ms | 3604 KiB |
| test_0055.txt | AC | 1905 ms | 3636 KiB |
| test_0056.txt | AC | 1906 ms | 3584 KiB |
| test_0057.txt | AC | 1913 ms | 3564 KiB |
| test_0058.txt | AC | 1907 ms | 3592 KiB |
| test_0059.txt | AC | 1921 ms | 3604 KiB |
| test_0060.txt | AC | 1916 ms | 3604 KiB |
| test_0061.txt | AC | 1905 ms | 3580 KiB |
| test_0062.txt | AC | 1911 ms | 3528 KiB |
| test_0063.txt | AC | 1916 ms | 3632 KiB |
| test_0064.txt | AC | 1911 ms | 3692 KiB |
| test_0065.txt | AC | 1907 ms | 3668 KiB |
| test_0066.txt | AC | 1903 ms | 3584 KiB |
| test_0067.txt | AC | 1914 ms | 3484 KiB |
| test_0068.txt | AC | 1906 ms | 3612 KiB |
| test_0069.txt | AC | 1921 ms | 3580 KiB |
| test_0070.txt | AC | 1917 ms | 3632 KiB |
| test_0071.txt | AC | 1904 ms | 3760 KiB |
| test_0072.txt | AC | 1908 ms | 3588 KiB |
| test_0073.txt | AC | 1913 ms | 3668 KiB |
| test_0074.txt | AC | 1907 ms | 3488 KiB |
| test_0075.txt | AC | 1903 ms | 3528 KiB |
| test_0076.txt | AC | 1918 ms | 3604 KiB |
| test_0077.txt | AC | 1908 ms | 3648 KiB |
| test_0078.txt | AC | 1915 ms | 3584 KiB |
| test_0079.txt | AC | 1913 ms | 3616 KiB |
| test_0080.txt | AC | 1918 ms | 3632 KiB |
| test_0081.txt | AC | 1915 ms | 3524 KiB |
| test_0082.txt | AC | 1924 ms | 3628 KiB |
| test_0083.txt | AC | 1918 ms | 3628 KiB |
| test_0084.txt | AC | 1933 ms | 3488 KiB |
| test_0085.txt | AC | 1915 ms | 3524 KiB |
| test_0086.txt | AC | 1926 ms | 3764 KiB |
| test_0087.txt | AC | 1927 ms | 3688 KiB |
| test_0088.txt | AC | 1924 ms | 3644 KiB |
| test_0089.txt | AC | 1913 ms | 3604 KiB |
| test_0090.txt | AC | 1914 ms | 3632 KiB |
| test_0091.txt | AC | 1908 ms | 3608 KiB |
| test_0092.txt | AC | 1915 ms | 3764 KiB |
| test_0093.txt | AC | 1908 ms | 3632 KiB |
| test_0094.txt | AC | 1904 ms | 3768 KiB |
| test_0095.txt | AC | 1937 ms | 3628 KiB |
| test_0096.txt | AC | 1922 ms | 3628 KiB |
| test_0097.txt | AC | 1909 ms | 3564 KiB |
| test_0098.txt | AC | 1920 ms | 3764 KiB |
| test_0099.txt | AC | 1908 ms | 3620 KiB |
| test_0100.txt | AC | 1915 ms | 3560 KiB |
| test_0101.txt | AC | 1906 ms | 3768 KiB |
| test_0102.txt | AC | 1917 ms | 3608 KiB |
| test_0103.txt | AC | 1912 ms | 3692 KiB |
| test_0104.txt | AC | 1924 ms | 3764 KiB |
| test_0105.txt | AC | 1912 ms | 3768 KiB |
| test_0106.txt | AC | 1909 ms | 3768 KiB |
| test_0107.txt | AC | 1911 ms | 3588 KiB |
| test_0108.txt | AC | 1917 ms | 3576 KiB |
| test_0109.txt | AC | 1914 ms | 3632 KiB |
| test_0110.txt | AC | 1907 ms | 3556 KiB |
| test_0111.txt | AC | 1918 ms | 3764 KiB |
| test_0112.txt | AC | 1906 ms | 3576 KiB |
| test_0113.txt | AC | 1924 ms | 3584 KiB |
| test_0114.txt | AC | 1910 ms | 3684 KiB |
| test_0115.txt | AC | 1907 ms | 3580 KiB |
| test_0116.txt | AC | 1909 ms | 3572 KiB |
| test_0117.txt | AC | 1913 ms | 3668 KiB |
| test_0118.txt | AC | 1920 ms | 3632 KiB |
| test_0119.txt | AC | 1918 ms | 3592 KiB |
| test_0120.txt | AC | 1914 ms | 3628 KiB |
| test_0121.txt | AC | 1912 ms | 3688 KiB |
| test_0122.txt | AC | 1920 ms | 3520 KiB |
| test_0123.txt | AC | 1914 ms | 3764 KiB |
| test_0124.txt | AC | 1905 ms | 3632 KiB |
| test_0125.txt | AC | 1925 ms | 3632 KiB |
| test_0126.txt | AC | 1904 ms | 3632 KiB |
| test_0127.txt | AC | 1908 ms | 3672 KiB |
| test_0128.txt | AC | 1919 ms | 3592 KiB |
| test_0129.txt | AC | 1915 ms | 3592 KiB |
| test_0130.txt | AC | 1909 ms | 3636 KiB |
| test_0131.txt | AC | 1903 ms | 3580 KiB |
| test_0132.txt | AC | 1916 ms | 3608 KiB |
| test_0133.txt | AC | 1903 ms | 3488 KiB |
| test_0134.txt | AC | 1910 ms | 3632 KiB |
| test_0135.txt | AC | 1903 ms | 3616 KiB |
| test_0136.txt | AC | 1905 ms | 3628 KiB |
| test_0137.txt | AC | 1913 ms | 3600 KiB |
| test_0138.txt | AC | 1919 ms | 3636 KiB |
| test_0139.txt | AC | 1909 ms | 3588 KiB |
| test_0140.txt | AC | 1913 ms | 3608 KiB |
| test_0141.txt | AC | 1909 ms | 3636 KiB |
| test_0142.txt | AC | 1915 ms | 3528 KiB |
| test_0143.txt | AC | 1903 ms | 3632 KiB |
| test_0144.txt | AC | 1914 ms | 3648 KiB |
| test_0145.txt | AC | 1906 ms | 3616 KiB |
| test_0146.txt | AC | 1925 ms | 3604 KiB |
| test_0147.txt | AC | 1913 ms | 3524 KiB |
| test_0148.txt | AC | 1915 ms | 3572 KiB |
| test_0149.txt | AC | 1905 ms | 3672 KiB |