zoukankan      html  css  js  c++  java
  • poj1681(枚举or高斯消元解mod2方程组)

    题目链接: http://poj.org/problem?id=1681

    题意: 有一个包含 n * n 个方格的正方形, w 表示其所在位置为白色, y 表示其所在位置为黄色. 对 (i, j) 位置进行一次操作则 (i, j), (i + 1, j), (i - 1, j), (i, j - 1),  (i, j + 1) 位置的颜色变为原来的相反状态, 输出让所有方格都变成白色所需的最少操作步数, 若不能使所有方格都变成白色,则输出 inf .

    思路: 这题和 poj 1222 (题解: http://www.cnblogs.com/geloutingyu/p/7565405.html) 类似, 同样也可以枚举第一行的所有操作, 或者解 mod2 方程组.

    解法1:

    注意要求出所有解法然后取操作数最小值.

     1 #include <iostream>
     2 #include <stdio.h>
     3 #include <string.h>
     4 using namespace std;
     5 
     6 const int inf = 1e9;
     7 const int MAXN = 1e2;
     8 int mp[MAXN][MAXN], sol[MAXN][MAXN];
     9 int n, ans = inf;
    10 
    11 int check(void){
    12     int gel[MAXN][MAXN], cnt = 0;
    13     memcpy(gel, mp, sizeof(mp));
    14     for(int i = 1; i <= n; i++){
    15         if(sol[1][i]){
    16             cnt++;
    17             gel[1][i] ^= 1;
    18             gel[1][i - 1] ^= 1;
    19             gel[1][i + 1] ^= 1;
    20             gel[2][i] ^= 1;
    21             gel[0][i] ^= 1;
    22         }
    23     }
    24     for(int i = 2; i <= n; i++){
    25         for(int j = 1; j <= n; j++){
    26             if(gel[i - 1][j]){
    27                 cnt++;
    28                 sol[i][j] = 1;
    29                 gel[i][j] ^= 1;
    30                 gel[i][j - 1] ^= 1;
    31                 gel[i][j + 1] ^= 1;
    32                 gel[i - 1][j] ^= 1;
    33                 gel[i + 1][j] ^= 1;
    34             }else sol[i][j] = 0;
    35         }
    36     }
    37     for(int i = 1; i <= n; i++){
    38         if(gel[n][i]) return inf;
    39     }
    40     return cnt;
    41 }
    42 
    43 void dfs(int m){
    44     if(m > n){
    45         ans = min(ans, check());
    46         return;
    47     }
    48     sol[1][m] = 1;
    49     dfs(m + 1);
    50     sol[1][m] = 0;
    51     dfs(m + 1);
    52 }
    53 
    54 int main(void){
    55     int t;
    56     string s;
    57     cin >> t;
    58     while(t--){
    59         cin >> n;
    60         for(int i = 1; i <= n; i++){
    61             cin >> s;
    62             for(int j = 0; j < s.size(); j++){
    63                 if(s[j] == 'w') mp[i][j + 1] = 1;
    64                 else mp[i][j + 1] = 0;
    65             }
    66         }
    67         ans = inf;
    68         dfs(1);
    69         if(ans == inf) cout << "inf" << endl;
    70         else cout << ans << endl;
    71     }
    72     return 0;
    73 }
    View Code

    解法2:

    注意对于存在变元的情况需要枚举变元的所有组合情况取操作数最小值.

      1 #include <iostream>
      2 #include <stdio.h>
      3 #include <algorithm>
      4 #include <string.h>
      5 using namespace std;
      6 
      7 const int inf = 1e9;
      8 const int MAXN = 3e2;
      9 int equ, var;//有equ个方程,var个变元,增广矩正行数为equ,列数为var+1,从0开始计数
     10 int a[MAXN][MAXN];//增广矩正
     11 int free_x[MAXN];//用来存储自由变元(多解枚举自由变元可以使用)
     12 int free_num;//自由变元个数
     13 int x[MAXN];//解集
     14 
     15 int Gauss(void){//返回-1表示无解,0表示有唯一解,否则返回自由变元个数
     16     int max_r, col, k;
     17     free_num = 0;
     18     for(k = 0, col = 0; k < equ && col < var; k++, col++){
     19         max_r = k;
     20         for(int i = k + 1; i < equ; i++){
     21             if(abs(a[i][col] > abs(a[max_r][col]))) max_r = i;
     22         }
     23         if(a[max_r][col] == 0){
     24             k--;
     25             free_x[free_num++] = col;//这个是变元
     26             continue;
     27         }
     28         if(max_r != k){
     29             for(int j = col; j < var + 1; j++){
     30                 swap(a[k][j], a[max_r][j]);
     31             }
     32         }
     33         for(int i = k + 1; i < equ; i++){
     34             if(a[i][col] != 0){
     35                 for(int j = col; j < var + 1; j++){
     36                     a[i][j] ^= a[k][j];
     37                 }
     38             }
     39         }
     40     }
     41     for(int i = k; i < equ; i++){
     42         if(a[i][col] != 0) return -1;//无解
     43     }
     44     if(k < var) return var - k;//返回自由变元个数
     45     for(int i = var - 1; i >= 0; i--){
     46         x[i] = a[i][var];
     47         for(int j = i + 1; j < var; j++){
     48             x[i] ^= (a[i][j] && x[j]);
     49         }
     50     }
     51     return 0;
     52 }
     53 
     54 void solve(void){
     55     int op = Gauss();
     56     if(op == -1) cout << "inf" << endl;//无解
     57     else if(op == 0){//存在唯一解
     58         int sol = 0;
     59         for(int i = 0; i < var; i++){
     60             sol += x[i];
     61         }
     62         cout << sol << endl;
     63     }else{//存在多解,需要枚举自由变元找到最小需要的操作数
     64         int sol = inf;
     65         int tot = 1 << op;//有op个变元,每个变元可取0或1,共有1<<op总情况
     66         for(int i = 0; i < tot; i++){//二进制枚举,i二进制位上为1的取1,为0的取0
     67             int cnt = 0;
     68             for(int j = 0; j < op; j++){
     69                 if(i & (1 << j)){//当前第j位变元取1
     70                     x[free_x[j]] = 1;
     71                     cnt++;
     72                 }else x[free_x[j]] = 0;
     73             }
     74             for(int j = var - op - 1; j >= 0; j--){
     75                 int idx;
     76                 for(idx = j; idx < var; idx++){
     77                     if(a[j][idx]) break;
     78                 }
     79                 x[idx] = a[j][var];
     80                 for(int l = idx + 1; l < var; l++){
     81                     if(a[j][l]) x[idx] ^= x[l];
     82                 }
     83                 cnt += x[idx];
     84             }
     85             sol = min(sol, cnt);
     86         }
     87         cout << sol << endl;
     88     }
     89 }
     90 
     91 int main(void){
     92     int t, n;
     93     string s;
     94     cin >> t;
     95     while(t--){
     96         cin >> n;
     97         equ = var = n * n;
     98         for(int i = 0; i < n; i++){
     99             cin >> s;
    100             for(int j = 0; j < n; j++){
    101                 int cnt = i * n + j;
    102                 if(s[j] == 'w') a[cnt][var] = 1;
    103                 else a[cnt][var] = 0;
    104                 x[cnt] = 0;
    105             }
    106         }
    107         for(int i = 0; i < equ; i++){//构造增广矩阵
    108            int x1 = i / n;
    109            int y1 = i % n;
    110            for(int j = 0; j < var; j++){
    111                int x2 = j / n;
    112                int y2 = j % n;
    113                if(abs(x1 - x2) + abs(y1 - y2) < 2) a[j][i] = 1;
    114                else a[j][i] = 0;
    115            }
    116         }
    117         solve();
    118     }
    119     return 0;
    120 }
    View Code
  • 相关阅读:
    配置ssl(阿里云+腾讯云)
    使用Nativefier将web页面打包为桌面应用
    临时切换淘宝源下载包
    ajax实现异步上传多图并且预览
    通过phpexcel插件导出报表功能实现
    ThinkPHP5.0自定义命令行的使用
    Longest Substring Without Repeating Characters
    计算机操作系统巡回置换算法
    HDU 2041 DP
    HDU 2044 DP (fibonacci)
  • 原文地址:https://www.cnblogs.com/geloutingyu/p/7571522.html
Copyright © 2011-2022 走看看