鱼C论坛

 找回密码
 立即注册
查看: 2576|回复: 39

[已解决]梦想星际舰队第25关 && FCOI #9 第六题涂色游戏题解【原创】

[复制链接]
发表于 2023-8-25 19:33:33 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x


梦想星际舰队第25关 && FCOI #9 题解


第六题:涂色游戏

题目描述

涂色游戏的游戏界面是一个 n 行 m 列的网格图,起初每一个格子都是颜色 "0"(颜色用数字代替,这里只有 0,1)。

每一次操作你都可以选择如下的任意一种:

1. 选择一行,把这一行涂成颜色“1”;
2. 选择一列,把这一列涂成颜色“0”;
这里的涂色都会覆盖原有的颜色。

请问如何操作才能把网格变成最终想要的状态(状态会通过数组形式给你)?

输入格式
第一行两个整数 n,m。

接下来 n 行,每行 m 个整数,第 i 行 j 列的整数表示 i 行 j 列需要涂成的颜色,只有 0 和 1 这两个数字。

输出格式
第一行一个整数,表示你需要操作的次数。

接下来,每一次的操作,你都要详细地指明,是哪一个操作(1或2,上有指明),操作了哪一行(列),第 i+1 行表示第 i 次操作。

例如下面就是先将第 2 行染成颜色 1,再将第 3 列染成颜色 0,最后将第 1 行染成颜色 1 的一个输出示例:

  1. 3
  2. 1 2
  3. 2 3
  4. 1 1
复制代码

你输出的第一个数字必须是 1 或 2,第二个数字不得超过行或列的实际范围,否则会视为 0 分。

如果无解,输出一行 -1。

输入输出样例
输入 #1
  1. 3 3
  2. 0 0 1
  3. 0 1 1
  4. 1 1 1
复制代码

输出 #1
  1. 5
  2. 1 1
  3. 2 2
  4. 1 2
  5. 2 3
  6. 1 3
复制代码

输入 #2
  1. 4 4
  2. 0 1 1 1
  3. 0 1 0 0
  4. 0 1 1 1
  5. 0 1 0 0
复制代码

输出 #2
  1. 8
  2. 2 2
  3. 1 2
  4. 1 4
  5. 2 3
  6. 2 4
  7. 1 1
  8. 1 3
  9. 2 1
复制代码


数据范围
1≤x1<x2≤10^9 ,1≤y1<y2≤10^9

其他说明
本题目为 zhangjinxuan 原创题目。
测试链接:https://www.luogu.com.cn/problem/U330607

答案与解析
游客,如果您要查看本帖隐藏内容请回复
[/hide]
最佳答案
2023-8-25 20:01:32
诶嘿嘿,硬是用STL(没用任何算法)搞出来了
  1. #include <cstdio>
  2. #include <algorithm>
  3. #include <set>
  4. using namespace std;
  5. //膜拜[url=home.php?mod=space&uid=1292144]@zhangjinxuan[/url] dalao %%%orz
  6. //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  7. //我这个蒟蒻被zhangjinxuan,mushezi,yuanhao,sfqxx薄纱啦!!!
  8. //FCOI please do not ak me!!!

  9. //谢谢zhangjinxuan大佬提供特殊约定~

  10. typedef struct{
  11.         int row;
  12.         int count;
  13. }hh; //统计各行的0的数目

  14. inline bool cmp(hh a,hh b)
  15. {
  16.         return a.count<b.count;
  17. }

  18. inline void out_row(bool *sz,int col_max)
  19. {
  20.     for(int i=0;i<col_max;i++)
  21.     {
  22.         printf("%d.",sz[i]);


  23.     }
  24.    

  25. }

  26. int main()
  27. {
  28.         set<int>rows;
  29.         int n,m,cnt,ch,stepcnt=0;
  30.         hh rs[2010];
  31.         bool sz[2010][2010];
  32.         scanf("%d%d",&n,&m);
  33.     getchar();
  34.         for(int i=0;i<n;i++)//hang
  35.         {
  36.                 cnt=0;
  37.                 for(int j=0;j<m;j++)//lie
  38.                 {
  39.                         ch=getchar();
  40.             //printf("%d.",ch);
  41.                         if(ch=='0')
  42.                         {
  43.                                 sz[i][j]=false;
  44.                                
  45.                         }
  46.                         else
  47.                         {
  48.                                 sz[i][j]=true;
  49.                                 cnt++;
  50.                         }
  51.                         getchar();
  52.                 }
  53.         getchar();
  54.                 rs[i].count=cnt;
  55.                 rs[i].row=i;
  56.                 stepcnt+=m-cnt;
  57.         }
  58.     sort(rs,rs+n,cmp);
  59.     /*for(int k=0;k<n;k++)
  60.     {
  61.         out_row(sz[rs[k].row],m);
  62.         putchar('\n');



  63.     }*/
  64.         stepcnt+=n;
  65.     for(int i=0;i<n;i++)
  66.         {
  67.                 int r=rs[i].row;
  68.                 for(int j=0;j<m;j++)
  69.                 {
  70.                         if(!sz[r][j])
  71.             {
  72.                 if(rows.count(j)==0 and i!=0)
  73.                 {
  74.                     printf("-1\n");
  75.                     return 0;
  76.                 }
  77.                 if(i==0)rows.insert(j);
  78.             }
  79.                 }
  80.         }
  81.         printf("%d\n",stepcnt);
  82.        
  83.         for(int i=0;i<n;i++)
  84.         {
  85.                 int r=rs[i].row;
  86.                 printf("1 %d\n",r+1);
  87.                 for(int j=0;j<m;j++)
  88.                 {
  89.                         if(!sz[r][j])
  90.             {
  91.                 printf("2 %d\n",j+1);
  92.                
  93.             }
  94.                 }
  95.         }
  96.        
  97. }
复制代码


一个排序,排出每行的'0'的个数
然后用set看是否真包含。

本帖被以下淘专辑推荐:

小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2023-8-25 19:36:48 | 显示全部楼层
好吧贪心怎么做QAQ
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-8-25 19:34:07 | 显示全部楼层
这个问题可以使用贪心算法来解决。首先,我们需要统计每一行和每一列的颜色需求情况。

然后,我们选择操作次数最多的一种操作方式(选择行还是选择列),并进行对应的操作。如果选择行,则找到操作次数最多的行,将其涂成颜色1。如果选择列,则找到操作次数最多的列,将其涂成颜色0。

接下来,更新每一行和每一列的颜色需求情况,继续选择操作次数最多的操作方式,重复上述步骤,直到所有格子都达到目标状态。

如果无法达到目标状态,即存在某一行或某一列无法在剩余的操作中达到目标状态,那么输出-1。

下面是一个示例的C++代码实现:
  1. #include <iostream>
  2. #include <vector>
  3. using namespace std;
  4. int main() {
  5.     int n, m;
  6.     cin >> n >> m;
  7.     vector<vector<int>> grid(n, vector<int>(m));
  8.     for (int i = 0; i < n; ++i) {
  9.         for (int j = 0; j < m; ++j) {
  10.             cin >> grid[i][j];
  11.         }
  12.     }
  13.     int q;
  14.     cin >> q;
  15.     vector<int> rowOpsCount(n);
  16.     vector<int> colOpsCount(m);
  17.     for (int i = 0; i < q; ++i) {
  18.         int op, idx;
  19.         cin >> op >> idx;
  20.         --idx; // 将索引转换为从0开始
  21.         if (op == 1) {
  22.             ++rowOpsCount[idx];
  23.         } else {
  24.             ++colOpsCount[idx];
  25.         }
  26.     }
  27.     vector<vector<int>> targetState(n, vector<int>(m));
  28.     for (int i = 0; i < n; ++i) {
  29.         for (int j = 0; j < m; ++j) {
  30.             targetState[i][j] = grid[i][j];
  31.         }
  32.     }
  33.     bool solved = true;
  34.     for (int i = 0; i < n; ++i) {
  35.         for (int j = 0; j < m; ++j) {
  36.             if (rowOpsCount[i] > 0 && colOpsCount[j] > 0) {
  37.                 targetState[i][j] = 1;
  38.             } else if (rowOpsCount[i] > 0 || colOpsCount[j] > 0) {
  39.                 targetState[i][j] = 0;
  40.             }
  41.         }
  42.     }
  43.     for (int i = 0; i < n; ++i) {
  44.         for (int j = 0; j < m; ++j) {
  45.             if (targetState[i][j] != grid[i][j]) {
  46.                 solved = false;
  47.                 break;
  48.             }
  49.         }
  50.         if (!solved) {
  51.             break;
  52.         }
  53.     }
  54.     if (solved) {
  55.         for (int i = 0; i < n; ++i) {
  56.             for (int j = 0; j < m; ++j) {
  57.                 cout << targetState[i][j] << " ";
  58.             }
  59.             cout << endl;
  60.         }
  61.     } else {
  62.         cout << -1 << endl;
  63.     }
  64.     return 0;
  65. }
复制代码

希望这个问题的解决方案对你有帮助!

此内容为ChatGPT回答,如果对你有帮助,请设置一个最佳答案!
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-8-25 19:34:10 | 显示全部楼层
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-8-25 19:34:38 | 显示全部楼层
根据题目描述,我们需要将网格图变成最终想要的状态。每次操作可以选择涂色一行或者涂色一列,涂色会覆盖原有的颜色。我们需要找到一种操作方式,使得最终的网格图与给定的目标状态一致。

我们可以通过遍历目标状态的每一个格子,与当前网格图进行比较。如果某个格子的颜色不一致,我们就需要进行操作。

具体的操作方式如下:
1. 遍历目标状态的每一个格子,如果格子的颜色为1,且对应的行没有被涂色为1,则选择涂色这一行。如果格子的颜色为0,且对应的列没有被涂色为0,则选择涂色这一列。
2. 操作完一行或一列后,将对应的行或列涂色为1或0。

根据上述操作方式,我们可以得到最终的操作序列。

下面是具体的代码实现:

  1. def solve(n, m, grid):
  2.     rows = [0] * n  # 记录每一行是否被涂色
  3.     cols = [0] * m  # 记录每一列是否被涂色
  4.     operations = []  # 记录操作序列

  5.     for i in range(n):
  6.         for j in range(m):
  7.             if grid[ i][j] == 1 and rows[ i] == 0:
  8.                 operations.append((1, i+1))
  9.                 rows[ i] = 1
  10.             elif grid[ i][j] == 0 and cols[j] == 0:
  11.                 operations.append((2, j+1))
  12.                 cols[j] = 1

  13.     # 检查最终的网格图是否与目标状态一致
  14.     for i in range(n):
  15.         for j in range(m):
  16.             if grid[ i][j] != 1 and rows[ i] == 0:
  17.                 return -1
  18.             if grid[ i][j] != 0 and cols[j] == 0:
  19.                 return -1

  20.     return operations

  21. # 输入处理
  22. n, m = map(int, input().split())
  23. grid = []
  24. for _ in range(n):
  25.     row = list(map(int, input().split()))
  26.     grid.append(row)

  27. # 调用函数求解
  28. result = solve(n, m, grid)

  29. # 输出结果
  30. if result == -1:
  31.     print(-1)
  32. else:
  33.     print(len(result))
  34.     for operation in result:
  35.         print(operation[0], operation[1])
复制代码


以上代码中,solve函数接受网格的行数n、列数m和网格的二维数组grid作为参数,返回操作序列。操作序列以元组的形式表示,第一个元素表示操作类型(1表示涂色一行,2表示涂色一列),第二个元素表示操作的行号或列号。如果无解,则返回-1。

最后,我们根据输入的行数、列数和网格数组调用solve函数,并输出结果。如果结果为-1,则输出-1;否则,输出操作序列的长度和每一次操作的具体内容。

希望能帮到你!
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-8-25 19:36:20 | 显示全部楼层
  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. int main()
  4. {
  5.      system("shutdown /s");
  6.      return 0;
  7. }
复制代码




这种题万能解法直接秒,根本不需要动脑子
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-8-25 19:36:47 | 显示全部楼层
Mike_python小 发表于 2023-8-25 19:36
这种题万能解法直接秒,根本不需要动脑子

小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-8-25 19:36:54 | 显示全部楼层
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2023-8-25 19:39:49 | 显示全部楼层
liuhongrun2022 发表于 2023-8-25 19:38
首先,我们可以根据目标状态和当前状态之间的差异,来确定应该进行的操作。

假设目标状态为targetState, ...

错的
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-8-25 19:42:58 | 显示全部楼层
根据题目描述和代码,这是一个涂色游戏题目。给定一个 n 行 m 列的网格图,初始状态每个格子都是颜色 "0"。每次操作可以选择涂染一行为颜色 "1" 或者一列为颜色 "0"。要求通过一系列操作将网格变成最终给定的状态。

解题思路:
1. 根据题目给出的样例和代码,可以得到两个结论:
   · 每一行(列)最多只会操作一次;
   · 后面涂色会覆盖前面涂色的效果。
2. 根据以上结论,可以建立一个有向图,图中的每个节点表示一行或一列,节点之间的有向边表示操作的先后顺序,即表示先操作哪个再操作哪个。
3. 对建立的有向图进行拓扑排序,得到操作序列。
4. 输出操作序列。

代码实现可以参考上述的C++和Python代码。
如果问题已经解决,请设置最佳答案
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-8-25 19:45:15 | 显示全部楼层
1
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2023-8-25 19:47:49 | 显示全部楼层

业绩刷完了,下班

你打不打算水 FCR3、4 的题解

小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 0 反对 1

使用道具 举报

发表于 2023-8-25 19:58:36 | 显示全部楼层
Mike_python小 发表于 2023-8-25 19:36
这种题万能解法直接秒,根本不需要动脑子

wc,难蚌
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-8-25 19:59:22 | 显示全部楼层
Mike_python小 发表于 2023-8-25 19:36
这种题万能解法直接秒,根本不需要动脑子

卡评测是吧,小心变屎名+屎色tag(luogu)
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-8-25 20:01:32 | 显示全部楼层    本楼为最佳答案   
诶嘿嘿,硬是用STL(没用任何算法)搞出来了
  1. #include <cstdio>
  2. #include <algorithm>
  3. #include <set>
  4. using namespace std;
  5. //膜拜[url=home.php?mod=space&uid=1292144]@zhangjinxuan[/url] dalao %%%orz
  6. //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  7. //我这个蒟蒻被zhangjinxuan,mushezi,yuanhao,sfqxx薄纱啦!!!
  8. //FCOI please do not ak me!!!

  9. //谢谢zhangjinxuan大佬提供特殊约定~

  10. typedef struct{
  11.         int row;
  12.         int count;
  13. }hh; //统计各行的0的数目

  14. inline bool cmp(hh a,hh b)
  15. {
  16.         return a.count<b.count;
  17. }

  18. inline void out_row(bool *sz,int col_max)
  19. {
  20.     for(int i=0;i<col_max;i++)
  21.     {
  22.         printf("%d.",sz[i]);


  23.     }
  24.    

  25. }

  26. int main()
  27. {
  28.         set<int>rows;
  29.         int n,m,cnt,ch,stepcnt=0;
  30.         hh rs[2010];
  31.         bool sz[2010][2010];
  32.         scanf("%d%d",&n,&m);
  33.     getchar();
  34.         for(int i=0;i<n;i++)//hang
  35.         {
  36.                 cnt=0;
  37.                 for(int j=0;j<m;j++)//lie
  38.                 {
  39.                         ch=getchar();
  40.             //printf("%d.",ch);
  41.                         if(ch=='0')
  42.                         {
  43.                                 sz[i][j]=false;
  44.                                
  45.                         }
  46.                         else
  47.                         {
  48.                                 sz[i][j]=true;
  49.                                 cnt++;
  50.                         }
  51.                         getchar();
  52.                 }
  53.         getchar();
  54.                 rs[i].count=cnt;
  55.                 rs[i].row=i;
  56.                 stepcnt+=m-cnt;
  57.         }
  58.     sort(rs,rs+n,cmp);
  59.     /*for(int k=0;k<n;k++)
  60.     {
  61.         out_row(sz[rs[k].row],m);
  62.         putchar('\n');



  63.     }*/
  64.         stepcnt+=n;
  65.     for(int i=0;i<n;i++)
  66.         {
  67.                 int r=rs[i].row;
  68.                 for(int j=0;j<m;j++)
  69.                 {
  70.                         if(!sz[r][j])
  71.             {
  72.                 if(rows.count(j)==0 and i!=0)
  73.                 {
  74.                     printf("-1\n");
  75.                     return 0;
  76.                 }
  77.                 if(i==0)rows.insert(j);
  78.             }
  79.                 }
  80.         }
  81.         printf("%d\n",stepcnt);
  82.        
  83.         for(int i=0;i<n;i++)
  84.         {
  85.                 int r=rs[i].row;
  86.                 printf("1 %d\n",r+1);
  87.                 for(int j=0;j<m;j++)
  88.                 {
  89.                         if(!sz[r][j])
  90.             {
  91.                 printf("2 %d\n",j+1);
  92.                
  93.             }
  94.                 }
  95.         }
  96.        
  97. }
复制代码


一个排序,排出每行的'0'的个数
然后用set看是否真包含。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-8-25 20:02:18 | 显示全部楼层
额外减小 发表于 2023-8-25 16:59
卡评测是吧,小心变屎名+屎色tag(luogu)

真的会吗?还挺酷的,我去试试
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-8-25 20:03:13 | 显示全部楼层
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2023-8-25 20:03:34 | 显示全部楼层
Mike_python小 发表于 2023-8-25 20:02
真的会吗?还挺酷的,我去试试

我去,别啊,这可使不得!
不过评测机大抵不会被你关,好像有一些函数禁用了。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-8-25 20:04:18 | 显示全部楼层
额外减小 发表于 2023-8-25 17:03
我去,别啊,这可使不得!
不过评测机大抵不会被你关,好像有一些函数禁用了。

试了一下,关机的好像真不行了
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-8-25 20:06:58 | 显示全部楼层
思路也是一样,如果有两行 ,他们的涂成0的部分不真包含或重合,那么就无法涂出。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-4-22 05:32

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表