Submission #71090490
Source Code Expand
Copy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
הההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההה
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#define INF INT64_C(101010101010101010)
int N;
int a[18][18];
#if 1
#if 1
#define USE_POOL
#endif
#define MOD_BY 95295899
#define MULT 13790611
#ifdef USE_POOL
struct memo_s {
int64_t ans;
uint32_t query;
int next;
};
#define STATUS_MAX 51234567
int pool_pos = 1;
struct memo_s pool[STATUS_MAX];
int memo[MOD_BY];
#else
struct memo_s {
int cur, left;
int64_t ans;
struct memo_s* next;
};
struct memo_s* memo[MOD_BY];
#endif
int64_t* get_memo(int cur, int left) {
int hash = (int)(((long long)cur * MULT + left) % MOD_BY);
#ifdef USE_POOL
uint32_t query = ((uint32_t)cur << 16) | (uint32_t)left;
int* pmemo = &memo[hash];
while (*pmemo > 0) {
if (pool[*pmemo].query == query) {
return &pool[*pmemo].ans;
}
pmemo = &pool[*pmemo].next;
}
if (pool_pos >= STATUS_MAX) {
puts("ERROR: too many status!");
exit(42);
}
*pmemo = pool_pos++;
pool[*pmemo] = (struct memo_s){ -INF, query, 0 };
return &pool[*pmemo].ans;
#else
struct memo_s** pmemo = &memo[hash];
while (*pmemo != NULL) {
if ((*pmemo)->cur == cur && (*pmemo)->left == left) {
return &(*pmemo)->ans;
}
pmemo = &(*pmemo)->next;
}
*pmemo = malloc(sizeof(**pmemo));
if (*pmemo == NULL) exit(2);
**pmemo = (struct memo_s){ cur, left, -INF, NULL };
return &(*pmemo)->ans;
#endif
}
#elif 0
int64_t* memos[1 << 18];
int64_t* get_memo(int cur, int left) {
int zerocnt = 0, cur2 = 0;
int i;
for (i = 0; i < N; i++) {
if (((left >> i) & 1) == 0) {
cur2 |= ((cur >> i) & 1) << zerocnt;
zerocnt++;
}
}
if (memos[left] == NULL) {
memos[left] = calloc(1 << zerocnt, sizeof(*memos[left]));
if (memos[left] == NULL) exit(2);
for (i = 0; i < (1 << zerocnt); i++) memos[left][i] = -INF;
}
return &memos[left][cur2];
}
#else
#define STATUS_MAX 51234567
int cmp(const void* x, const void* y) {
uint32_t a = *(const uint32_t*)x, b = *(const uint32_t*)y;
return (a > b) - (a < b);
}
int status_cnt = 0;
uint32_t status_list[STATUS_MAX];
int64_t memo[STATUS_MAX];
int64_t* get_memo(int cur, int left) {
int l, r;
uint32_t query;
if (status_cnt == 0) {
int i, j, k;
for (i = 0; i < (1 << N); i++) {
int zeros[18], zerocnt = 0;
for (j = 0; j < N; j++) {
if (((i >> j) & 1) == 0) zeros[zerocnt++] = j;
}
for (j = 0; j < (1 << zerocnt); j++) {
uint32_t x = 0;
for (k = 0; k < zerocnt; k++) {
x |= ((j >> k) & 1) << zeros[k];
}
if (status_cnt >= STATUS_MAX) {
puts("ERROR: too many status!");
exit(42);
}
status_list[status_cnt++] = (x << 16) | (uint32_t)i;
}
}
qsort(status_list, status_cnt, sizeof(*status_list), cmp);
for (i = 0; i < status_cnt; i++) memo[i] = -INF;
}
l = 0;
r = status_cnt - 1;
query = ((uint32_t)cur << 16) | (uint32_t)left;
while (l <= r) {
int m = l + (r - l) / 2;
if (status_list[m] == query) return &memo[m];
else if (status_list[m] < query) l = m + 1;
else r = m - 1;
}
printf("ERROR: cur = %d, left = %d not found!\n", cur, left);
exit(72);
}
#endif
int64_t score_cache[1 << 18];
int poscnt[1 << 18];
int poses[1 << 18][18];
int64_t calc(int cur, int left) {
if (cur == 0 && left == 0) {
return 0;
} else {
int64_t ans = -INF;
int64_t *pmemo = get_memo(cur, left);
int i, j;
if (*pmemo > -INF) return *pmemo;
/* 精算する */
if (cur != 0) {
if (score_cache[cur]) {
ans = ~score_cache[cur];
} else {
ans = 0;
for (i = 0; i < N; i++) {
if ((cur >> i) & 1) {
for (j = i + 1; j < N; j++) {
if ((cur >> j) & 1) ans += a[i][j];
}
}
}
score_cache[cur] = ~ans;
}
ans += calc(0, left);
}
/* グループに追加する */
for (i = 0; i < poscnt[left] && (cur != 0 || i < 1); i++) {
int64_t candidate = calc(cur | (1 << poses[left][i]), left & ~(1 << poses[left][i]));
if (candidate > ans) ans = candidate;
}
return *pmemo = ans;
}
}
int main(void) {
int i, j;
if (scanf("%d", &N) != 1) return 1;
for (i = 0; i < N; i++) {
for (j = 0; j < N; j++) {
if (scanf("%d", &a[i][j]) != 1) return 1;
}
}
for (i = 0; i < (1 << N); i++) {
for (j = 0; j < N; j++) {
if ((i >> j) & 1) {
poses[i][poscnt[i]++] = j;
}
}
}
printf("%" PRId64 "\n", calc(0, (1 << N) - 1));
return 0;
}
/*
メモ化探索をする
状態:
* cur:現在のグループに入っているうさぎの集合
* left:まだグループに入っていないうさぎの集合
行動の選択肢:
* 現在のグループを確定し、精算する
* 現在のグループにうさぎを1羽選んで入れる
そのままやると (1<<16) * (1<<16) で死にそうだけど、
curとleftは被らないので……まあなんとかなるやろ (雑)
>>> cnt = 0
>>> for i in range(1<<16):
... cc = 0
... for j in range(16):
... if ((i >> j) & 1) != 0:
... cc += 1
... cnt += 1 << cc
...
>>> cnt
43046721
試してみるとうまくいかない
なんか枝を刈るべき
→ cur が空のとき、必ず最初の left をグループに入れる
*/
Submission Info
| Submission Time |
|
| Task |
U - Grouping |
| User |
mikecat |
| Language |
C (gcc 12.2.0) |
| Score |
100 |
| Code Size |
5267 Byte |
| Status |
AC |
| Exec Time |
1336 ms |
| Memory |
492488 KiB |
Judge Result
| Set Name |
All |
| Score / Max Score |
100 / 100 |
| Status |
|
| Set Name |
Test Cases |
| All |
0_00, 0_01, 0_02, 0_03, 1_00, 1_01, 1_02, 1_03, 1_04, 1_05, 1_06, 1_07, 1_08, 1_09, 1_10, 1_11, 1_12, 1_13, 1_14, 1_15, 1_16, 1_17, 1_18, 1_19 |
| Case Name |
Status |
Exec Time |
Memory |
| 0_00 |
AC |
0 ms |
1768 KiB |
| 0_01 |
AC |
0 ms |
1684 KiB |
| 0_02 |
AC |
0 ms |
1804 KiB |
| 0_03 |
AC |
1251 ms |
492328 KiB |
| 1_00 |
AC |
0 ms |
1668 KiB |
| 1_01 |
AC |
1229 ms |
492380 KiB |
| 1_02 |
AC |
1230 ms |
492388 KiB |
| 1_03 |
AC |
1231 ms |
492388 KiB |
| 1_04 |
AC |
1335 ms |
492356 KiB |
| 1_05 |
AC |
1291 ms |
492324 KiB |
| 1_06 |
AC |
1328 ms |
492384 KiB |
| 1_07 |
AC |
1296 ms |
492488 KiB |
| 1_08 |
AC |
1319 ms |
492404 KiB |
| 1_09 |
AC |
1328 ms |
492328 KiB |
| 1_10 |
AC |
1308 ms |
492388 KiB |
| 1_11 |
AC |
1336 ms |
492488 KiB |
| 1_12 |
AC |
1222 ms |
492400 KiB |
| 1_13 |
AC |
1226 ms |
492400 KiB |
| 1_14 |
AC |
1233 ms |
492352 KiB |
| 1_15 |
AC |
1255 ms |
492340 KiB |
| 1_16 |
AC |
1241 ms |
492468 KiB |
| 1_17 |
AC |
1225 ms |
492480 KiB |
| 1_18 |
AC |
1241 ms |
492412 KiB |
| 1_19 |
AC |
1226 ms |
492488 KiB |