1 条题解

  • 0
    @ 2025-8-24 23:07:42

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar ycy1124
    ENTJ-A | 有事私。| 清关了,私信基本也不会回关(除非满足条件),但可以支持小号回关 | 出去玩去了。不在线。微信可能上。

    搬运于2025-08-24 23:07:42,当前版本为作者最后更新于2025-08-19 14:37:27,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    题意

    我们有一个 n×nn\times n 的全 00 矩阵,现在我们希望用一些将某一行或某一列全部染成 2,32,3 的操作使其变成目标矩阵并构造方案或输出无解。

    思路

    我们某一行或者某一列一定不会被染色多次,因此操作次数小于等于 4×1034\times 10^3 显然是满足的。我们发现,当我们的当前矩阵有某一行或者某一列均为同一种颜色时,我们显然可以在末尾添加一次操作将这行或列染色掉,然后便可以将这一行或列直接在当前矩阵中删除掉。由于我们是倒序加入操作的,所以并不需要考虑对其它操作的影响。

    考虑我们这样一直将可以染色的行或列全部删除直到没有可删除的行或列了该怎么办。我们发现,如果此时还有没有被染色正确的点的话就一定无解了。为什么呢,我们发现,此时无论如何染某一行或列,都一定会有不满足最终矩阵的位置。因此我们只需要一直操作到不能继续操作,再按照找到的操作还原矩阵判断一下与最终矩阵相不相同即可。

    代码

    #include<bits/stdc++.h>
    #define N 2000 + 39
    using namespace std;
    int a[N][N], h[3][N], l[3][N], n, c[N][N];
    bool vis[2][N];
    struct Node
    {
    	int op, x, color;
    };
    stack<Node>ans, check;
    queue<Node>q;
    int main()
    {
    	ios :: sync_with_stdio(0), cin.tie(0), cout.tie(0);
    	cin >> n;
    	for(int i = 1; i <= n; i ++)
    	{
    		for(int j = 1; j <= n; j ++)
    		{
    			cin >> a[i][j];
    			h[a[i][j]][i] ++;
    			l[a[i][j]][j] ++;//我们记录每一行每一列0,1,2的个数,这样就能快速找到全1或2的行或列
    		}
    	}
    	for(int i = 1; i <= n; i ++)
    	{
    		if(h[0][i])//有0一定不能染色
    		{
    			vis[0][i] = 1;//判断一行或一列能否被染色,有0的显然不行
    		}
    		else
    		{
    			if(!h[1][i])
    			{
    				vis[0][i] = 1;
    				q.push({1, i, 2});
    			}
    			else if(!h[2][i])
    			{
    				vis[0][i] = 1;
    				q.push({1, i, 1});
    			}
    		}
    		if(l[0][i])
    		{
    			vis[1][i] = 1;
    		}
    		else
    		{
    			if(!l[1][i])
    			{
    				vis[1][i] = 1;
    				q.push({2, i, 2}); 
    			}
    			else if(!l[2][i])
    			{
    				vis[1][i] = 1;
    				q.push({2, i, 1});
    			}
    		}
    	}
    	while(q.size())//一直寻找可以被操作的位置
    	{
    		check.push(q.front());
    		ans.push(q.front());
    		int op = q.front().op, x = q.front().x, color = q.front().color;
    		q.pop();
    		if(op == 1)
    		{
    			for(int i = 1; i <= n; i ++)
    			{
    				if(vis[1][i])
    				{
    					continue;
    				}
    				l[color][i] --;//修改行的时候更新每一列
    				if(l[color][i] == 0)
    				{
    					vis[1][i] = 1;
    					q.push({2, i, color == 1 ? 2 : 1});
    				}
    			}
    		}
    		else
    		{
    			for(int i = 1; i <= n; i ++)
    			{
    				if(vis[0][i])
    				{
    					continue;
    				}
    				h[color][i] --;//同理
    				if(h[color][i] == 0)
    				{
    					vis[0][i] = 1;
    					q.push({1, i, color == 1 ? 2 : 1});
    				}
    			}
    		}
    	}
    	while(check.size())//还原一下我们的操作的最终矩阵
    	{
    		int op = check.top().op, x = check.top().x, color = check.top().color;
    		check.pop();
    		for(int i = 1; i <= n; i ++)
    		{
    			if(op == 1)
    			{
    				c[x][i] = color;
    			}
    			else
    			{
    				c[i][x] = color;
    			}
    		}
    	}
    	for(int i = 1; i <= n; i ++)
    	{
    		for(int j = 1; j <= n; j ++)
    		{
    			if(c[i][j] != a[i][j])
    			{
    				cout << -1;//不合法输出-1
    				return 0;
    			}
    		}
    	}
    	cout << ans.size() << '\n';
    	while(ans.size())
    	{
    		cout << ans.top().op << ' ' << ans.top().x << ' ' << ans.top().color << '\n';
    		ans.pop();
    	}
    	return 0;
    }
    

    AC 记录

    • 1

    信息

    ID
    11217
    时间
    1000ms
    内存
    500MiB
    难度
    4
    标签
    递交数
    0
    已通过
    0
    上传者