zoj 3780 Paint the Grid Again 拓扑排序

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/ccsu_cat/article/details/82118252

zoj 3780

题意:你可以一行全涂X,也可以一列全涂O,可以覆盖,输出字典序最小的一个涂色方案,使得从一个空白的n*n的矩形可以变成给定的矩形。

思路:正过来想不好想,可以反过来想,如果一行全为X,那么这一行肯定是最后涂的,那么就把这一行X全部擦掉,如果这一步造成某一列只剩下O,那么剩下的涂色方案中,这一列是最后涂的颜色,这么一想,有点像拓扑排序,设R数组度数为每一行O的个数,C数组度数为每一列X的个数,那么接下来要做的就是拓扑排序,将所有度数为0的点进队,如果出队点R[ i ],接下来会造成所有的C点度数减一,如果有一个点C[ j ]的度数因此变为0,将C[ j ]入队即可。每次出队点C[ i ],也会造成多有的R点度数减一,同理。

#include<cstdio>
#include<cstring>
#include<queue>
#include<stack>
#include<algorithm>
using namespace std;
const int maxn=505;
char s[maxn][maxn];
int n,r[maxn],c[maxn];
struct node
{
	char c;
	int num;
	bool operator<(const node& t)const//优先队列输出字典序最大,然后用栈变成字典序最小 
	{                                  
		if(c==t.c)
		return num<t.num;
		return c<t.c;
	}
}no;
void toposort()
{
	stack<node>sta;
	priority_queue<node>q;
	for(int i=1;i<=n;i++)
	if(!r[i])
	q.push((node){'R',i});
	else if(!c[i])
	q.push((node){'C',i});
	int cnt1=0,cnt2=0;//分别记录涂了的行数和列数 
	while(!q.empty())
	{
		no=q.top();q.pop();
		if(cnt1<n&&cnt2<n)sta.push(no);//如果行数涂满了或者列数涂满了,就不用涂色了 
		if(no.c=='R')cnt1++;
		else cnt2++;
		if(no.c=='R')
		for(int i=1;i<=n;i++)
		{
			c[i]--;
			if(!c[i])
			q.push((node){'C',i});
		}
		else
		for(int i=1;i<=n;i++)
		{
			r[i]--;
			if(!r[i])
			q.push((node){'R',i});
		}
	}
	int flag=1;
	for(int i=1;i<=n;i++)if(r[i]>0||c[i]>0)flag=0;//有些点的度数不为0,无解 
	if(!flag)
	puts("No solution");
	else
	while(!sta.empty())
	{
		no=sta.top();
		sta.pop();
		printf("%c%d",no.c,no.num);
		if(!sta.empty())
		printf(" ");
		else
		puts("");
	}
}
int main()
{
	int T;
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d",&n);
		for(int i=1;i<=n;i++)
		scanf("%s",s[i]+1);
		for(int i=1;i<=n;i++)
		{
			int cnt1=0,cnt2=0;
			for(int j=1;j<=n;j++)
			{
				if(s[i][j]=='O')
				cnt1++;
				if(s[j][i]=='X')
				cnt2++;
			}
			r[i]=cnt1,c[i]=cnt2;
		}
		toposort();
	}
}

猜你喜欢

转载自blog.csdn.net/ccsu_cat/article/details/82118252
今日推荐