codeforces 486B.OR in Matrix 解题报告

题目链接:http://codeforces.com/problemset/problem/486/B

题目意思:给出一个m行n列的矩阵B(每个元素只由0/1组成),问是否可以利用矩阵B,通过一定的运算逆回来求出矩阵A(行和列数都跟B相同)。可以的话输出"YES" 并输出矩阵A,否则输出 "NO"。运算如下:

    

     也就是,Bij 是通过 A 矩阵第 i 行中所有的数做 或(|) 运算接着再跟所有第 j 列中所有的数做 或 运算求出来的。or 运算就是除了所有元素都为 0 的情况,or出来的结果为0外,其他情况算出来都是1(至少有一个元素是 1 即可)。

    以下注释部分可以忽略~~~

    /******************************************

     我一开始的错误做法是利用两个数组 row[] 和 col[] ,初始化使得row[1]~row[m] 都为1,col[1]~col[n] 都为1。当 Bij = 0 时,令 row[i] = 0,col[j] = 0来表示第 i 行 和 第 j 列都必须要填 0。这样才能保证 or 出来的结果是0嘛~~然后找出矛盾,即如果b[i][j] = 0,它需要满足row[i] == 0 且 col[j] == 0;如果b[i][j] = 1,但遇到row[i] == 0 且 col[j] == 0,那么就表示有矛盾啦。最后就根据如果row[i] == 0 或者 col[j] == 0 就输出0,否则输出1。

    不过仔细想一下,其实填1的情况是比较复杂的,例如b[i][j] = 1,那么并不能确定究竟是因为row[i] = 1 还是 col [j] = 1,而输出如果仅仅是根据 row[i] == 0 或者 col[j] == 0 输出0是不对的,试想,因为只要保证其中一个(row[i] == 0 && col[j] == 1类似这种)是1即有可能输出1了。于是最终测试遇到这组数据的时候就呵呵了~~~(我的输出是9个0,明显是错的)

     1  0 0

     1  0 0     

    1  0 0

   如果按我的做法,那么分析结果是row[1] = 0, row[2] = 0, row[3] = 0,col[1] = 1,col[2] = 0,col[3] = 0。b[i][j] == 1 且 row[i] == 0 && col[j] == 0 是得不出矛盾的。例如b[1][1] = 1,它只是row[1] = 0,但col[1] != 0。

************************************************/

    正确的做法要用到逆向思维。首先根据b[i][j]构造出相应的a[i][j] 哪些数必定为1。如果b[i][j] = 0,那么a[i][0]~a[i][n-1] 都为0,a[0][j]~a[m-1][j] 都为0。那么逆回来就是如果a[i][j] = 1,那么b[i][0]~b[i][n-1]所有元素都为1,b[0][j] ~b[m-1][j]所有元素都为1,就是没有一个元素等于0!是不是很神奇呢~~~~然后利用矩阵a求出对应的b'[i][j](代码中是c[i][j]),然后对比b[i][j]是否跟c[i][j]不同,不同即引出矛盾。

      这种思维确实需要好好锻炼!!!

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstdlib>
 4 #include <cstring>
 5 using namespace std;
 6 
 7 const int maxn = 100 + 10;
 8 int a[maxn][maxn], b[maxn][maxn];
 9 int c[maxn][maxn];
10 
11 int main()
12 {
13     int m, n;
14     while (scanf("%d%d", &m, &n) != EOF)
15     {
16         for (int i = 0; i < m; i++)
17         {
18             for (int j = 0; j < n; j++)
19                 scanf("%d", &b[i][j]);
20         }
21         memset(a, 0, sizeof(a));
22         for (int i = 0; i < m; i++)   // 构造a矩阵
23         {
24             for (int j = 0; j < n; j++)
25             {
26                 bool ok = false;
27                 for (int l = 0; l < m; l++)  //
28                 {
29                     if (!b[l][j])          
30                         ok = true;
31                 }
32                 for (int l = 0; l < n; l++)  //
33                 {
34                     if (!b[i][l])
35                         ok = true;
36                 }
37                 if (!ok)          // a[i][j] 填1必须要满足b[0][j]~b[m-1][j]以及b[i][0]~b[i][n-1]没有一个元素等于0。
38                     a[i][j] = 1;
39             }
40         }
41         // 从a矩阵经计算应该得到的b矩阵
42         for (int i = 0; i < m; i++)
43         {
44             for (int j = 0; j < n; j++)
45             {
46                 if (a[i][j] == 1)
47                 {
48                     for (int l = 0; l < m; l++)
49                         c[l][j] = 1;
50                     for (int l = 0; l < n; l++)
51                         c[i][l] = 1;
52                 }
53             }
54         }
55         // 检查是否有矛盾
56         bool ok = true;
57         for (int i = 0; i < m && ok; i++)
58         {
59             for (int j = 0; j < n && ok; j++)
60             {
61                 if (c[i][j] != b[i][j])
62                 {
63                     ok = false;
64                     break;
65                 }
66             }
67         }
68         printf("%s\n", ok ? "YES" : "NO");
69         for (int i = 0; i < m && ok; i++)
70         {
71             for (int j = 0; j < n; j++)
72                 cout << a[i][j] << (j == n-1 ?  "\n" : " ");
73         }
74     }
75     return 0;
76 }

 

转载于:https://www.cnblogs.com/windysai/p/4092508.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值