NJUST 1743 Boring Game(2013南京邀请赛G题)(thx to _LT_zyc)

来源:互联网 发布:电脑消毒软件 编辑:程序博客网 时间:2024/05/29 19:03

  本做法是基于暴力枚举第一行走法的O((n^2)*(2^n))的方法的预处理优化版。

  首先做一个预处理,对于空白的棋盘,枚举第一行的走法,然后以把前n-1行复原成白的为目标,逐行向下推出下面n-1行的走法,记录下最后第n行的状态和对应走法的映射(可以用邻接表)。

  对于每组case,第一行不动,同样地,以把前n-1行复原成白的为目标,逐行向下推出下面n-1行的走法x,这时第n行残留下一个状态,找到该状态所映射到的预处理得到的走法y(y可能不唯一),将x与y叠加(取异或)就得到一个可行解,然后就是统计可行解中1的个数,再取最小值输出就好了。

  预处理的复杂度为O((n^3)*(2^n)),单组case复杂度为O(n^2)。在OJ上跑有点卡常数,我在统计1的个数那里加了个猥琐的常优才能过,不知道还有什么好方法能快速统计二进制数中1的个数。

// 1743aroslhy(Aros)Accepted 2424ms 1724KB GPP 1930 B 2013-05-19 12:51#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int MAX = 8, MAXN = MAX+5, MAXM = 1<<(MAX+1);int T, N, e, head[MAXN][1<<MAX], next[MAXM], cnt[1<<16];unsigned long long a[MAXN], v[MAXM];void Addedge(int n, int t, unsigned long long mov){v[e] = mov;next[e] = head[n][t]; head[n][t] = e++;}void Select(int N, unsigned long long &mat, unsigned long long &mov, int x, int y){mov ^= 1ULL<<(N*x+y);mat ^= 1ULL<<(N*x+y);if (x > 0)mat ^= 1ULL<<(N*(x-1)+y);if (x+1 < N)mat ^= 1ULL<<(N*(x+1)+y);if (y > 0)mat ^= 1ULL<<(N*x+y-1);if (y+1 < N)mat ^= 1ULL<<(N*x+y+1);}int Count(unsigned long long x){int pat = (1<<16)-1, res = 0;for (int i = 0; i < 4; i++)res += cnt[(x>>(i*16))&pat];return res;}int main(){memset(head, -1, sizeof(head));for (int n = 1; n <= 8; n++){int tot = 1<<n;for (int s = 0; s < tot; s++){unsigned long long mat = 0, mov = 0;for (int j = 0; j < n; j++) if (s&(1<<j))Select(n, mat, mov, 0, j);for (int i = 1; i < n; i++)for (int j = 0; j < n; j++) if (mat&(1ULL<<(n*(i-1)+j)))Select(n, mat, mov, i, j);int t = mat>>((n-1)*n);Addedge(n, t, mov);}}int tot = 1<<16;for (int i = 0; i < tot; i++)for (int j = 0; j < 16; j++) if (i&(1<<j))cnt[i]++;scanf("%d", &T);while (T--){scanf("%d", &N);unsigned long long mat = 0, mov = 0;for (int i = 0; i < N; i++){scanf("%llu", &a[i]);for (int j = 0; j < N; j++)mat ^= ((a[i]>>(N-j-1))&1)<<(N*i+j);}for (int i = 1; i < N; i++)for (int j = 0; j < N; j++) if (mat&(1ULL<<(N*(i-1)+j)))Select(N, mat, mov, i, j);int fin = mat>>((N-1)*N), ans = -1;for (int i = head[N][fin]; i != -1; i = next[i])ans = (ans != -1) ? min(ans, Count(mov^v[i])) : Count(mov^v[i]);printf("%d\n", ans);}return 0;}


原创粉丝点击