zoukankan      html  css  js  c++  java
  • Crosses Puzzles zoj 4018 (zju校赛)

    http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=5746

    题目大意:

    N*M的方格里,每个格子有一个指针,一开始指向上下左右四个方向中的一个,选一个格子点一次,那个格子的指针会顺时针转一下,接着被它指着的那个格子的针也会顺时针转一下,一直连锁下去。  构造一种不超过6000次点击的方案,使得所有针朝上。

    题解:
    $need[x][y]$表示这个格子的针转多少次可以朝上。

    $A[x][y]$表示这个格子主动转了多少次。

    $B[x][y]$表示这个格子由于受到边上格子的影响被动转了多少次。

    那么有:

    $A[x][y] + B[x][y] = 4 * K[x][y] + need[x][y]$. (等式1)

    $B[x][y] = sum (K[x'][y'] + [(x', y')转到朝上的过程中会影响到(x, y)]) $  (等式2)

    其中$(x', y')是和(x, y)相邻的格子$

    一开始先假设所有的 $K[x][y] = 0$,那么所有的$A[x][y]$ $B[x][y]$ 都可以计算出来。但是某些$A[x][y]$会是负数。

    考虑把一些$K[x][y]$加大。 如果把$K[x][y] += 1$, 为了使得之前的等式仍然成立,必须有$A[x][y] += 4$,所有和它相邻的格子(x', y')必须 $A[x'][y'] -= 1, B[x'][y'] += 1$。

    然后先本地开始乱shi:

    因为不超过6000步,平均每个格子60步。

    所以从上到下从左到右,如果发现当前格子的$A[x][y] <= 56$, 就不断让当前格子+4,和它相邻格子-1。

    这样做一次后,发现最外面的一圈的$A[x][y]$都是几十了。中间的还是会有一些负数。

    重复上面的过程,发现每做一次都会使得A为几十的圈子往里缩小。重复10次就ok了。

    思考:为什么所有让$A[x][y]>=0$ 就好了呢?

    因为一组合法的$A[x][y]$,可以解出所有的$B[x][y]$ 和 $K[x][y]$.且解是唯一的。

    证明: 把等式1中的B用K表示带入等式二,得到$N^2$个关于$K$的方程,$K$有$N^2$个变量,所以如果有解,解一定唯一。

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 #define MAXN 15
     5 
     6 int n, m;
     7 int a[MAXN][MAXN], x[MAXN][MAXN], y[MAXN][MAXN];
     8 int dx[] = {-1, 0, 1, 0};
     9 int dy[] = {0, 1, 0, -1};
    10 int ok[4][4], need[MAXN][MAXN];
    11 
    12 bool check(int x, int y)
    13 {
    14     return x >= 1 && x <= n && y <= m && y >= 1 && a[x][y] != -1;
    15 }
    16 
    17 int main()
    18 {
    19     //freopen("in.txt", "r", stdin);
    20     ok[0][1] = 1;
    21     ok[1][1] = ok[1][2] = 1;
    22     ok[2][1] = ok[2][2] = ok[2][3] = 1;
    23     
    24     int T;
    25     scanf("%d", &T);
    26     while (T--)
    27     {
    28         scanf("%d %d", &n, &m);
    29         for (int i = 1; i <= n; ++i)
    30         {
    31             for (int j = 1; j <= m; ++j)
    32             {
    33                 scanf("%d", &a[i][j]);
    34                 if (a[i][j] == -1) continue;
    35                 a[i][j] = (4 - a[i][j]) % 4;
    36                 need[i][j] = (4 - a[i][j]) % 4;
    37             }
    38         }
    39         memset(x, 0, sizeof(x));
    40         memset(y, 0, sizeof(y));
    41         int _i, _j;
    42         for (int i = 1; i <= n; ++i)
    43         {
    44             for (int j = 1; j <= m; ++j)
    45             {
    46                 if (a[i][j] == -1) continue; 
    47                 for (int d = 0; d < 4; ++d)
    48                 {
    49                     _i = i + dx[d], _j = j + dy[d];
    50                     if (check(_i, _j) && ok[d][a[_i][_j]])
    51                         ++y[i][j];
    52                 }
    53                 x[i][j] = need[i][j] - y[i][j];
    54             }
    55         }
    56         int iters = 10;
    57         while (iters--)
    58         {
    59             for (int i = 1; i <= n; ++i)
    60             {
    61                 for (int j = 1; j <= m; ++j)
    62                 {
    63                     if (a[i][j] == -1) continue;
    64                     while (x[i][j] + 4 <= 60)
    65                     {
    66                         x[i][j] += 4;
    67                         for (int d = 0; d < 4; ++d)
    68                         {
    69                             _i = i + dx[d], _j = j + dy[d];
    70                             if (check(_i, _j)) --x[_i][_j], ++y[_i][_j];
    71                         }
    72                     }
    73                 }
    74             }
    75         }
    76         vector<pair<int, int> > ans;
    77         for (int i = 1; i <= n; ++i)
    78         {
    79             for (int j = 1; j <= m; ++j)
    80             {
    81                 if (a[i][j] == -1) continue;
    82                 assert(x[i][j] >= 0);
    83                 while (x[i][j] > 0) --x[i][j], ans.push_back(make_pair(i, j));
    84             }
    85         }
    86         printf("%d
    ", ans.size());
    87         for (int i = 0; i < (int)ans.size(); ++i)
    88             printf("%d %d
    ", ans[i].first, ans[i].second);
    89     }
    90     
    91     return 0;
    92 }
  • 相关阅读:
    7人脸识别
    1图片视频文件操作基础
    3直方图与二值化,图像梯度
    6模板匹配(人脸匹配案例)
    基础习题
    碎片知识点整理
    详解:MySQL数据表损坏的正确修复方案
    前端开发:模块化 — 高效重构
    分享几个基于jQuery不错的前端相册展示插件代码
    程序员编程10年的心得和体会
  • 原文地址:https://www.cnblogs.com/vb4896/p/8820356.html
Copyright © 2011-2022 走看看