您的位置:首页 > 大数据 > 人工智能

zoj 3780 Paint the Grid Again 11届浙江省赛 (拓扑排序)

2017-01-14 10:36 435 查看
题意:

给定一块正方形区域,大小为n,现在你能对每一行每一列进行一次操作,你可以 把一行涂成黑色,或者把一列涂成白色,但是每行每列都只能操作一次。现在给你目标区域,X表示黑色,O表示白色,问经过怎样的操作可以让得到 这个目标区域。Rx表示把第x行涂成黑色,Cx表示把第x列涂成白色,按操作顺序输出,要求操作数最少,且字典序最小。如果不能得到输出No solution。

思路:

首先我们针对一个点来思考,如果这个点是白色的,那么这个点所在的列一定有涂成白色的操作,而且,这个点所在的行涂成黑色的操作一定在列操作之前。那么我们对于每一个点都能确定一个row i 和col j的关系,形成一个拓扑图。但是,需要考虑一点,如果这个点是白色,不能单纯的就讲这个点所在的列操作后于行操作加入到拓扑图当中,而要考虑,这个点所在的行是否存在黑色结点,如果不存在,那么说明这一行并不需要进行行操作,所以这个点就不产生拓扑关系,对于这个点来说直接列操作就好了。

所以实际的做法就是先记录每一行每一列是否需要进行涂色操作,在这个基础上对这一行或这一列的点统计入度(建立拓扑关系),然后就是用优先队列去维护每个入度为0的点,(之所以用优先队列维护是题目要求字典序最小,当然由于C小于R,所以应该让列操作在前面,我的操作是直接给行数+n),最后判断下有无环就好了。

总结:

这个题我坑在了判断是否有环上,对于有环的图我们肯定不能得到solution,但是我没考虑这个,而是直接看是否存在一开始就有入度为0的点,就wa了,因为即使存在入度为0的点,之后也可能存在环。

另外,n的大小是到500,我在数字转字符串的时候数组开小了,坑了我好久。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std;
char a[505][505];
int b[505][505];
int topo[1005]; //记录每个点的 入度,含义是列数和行数+n
int book[1005]; //记录行和列是否需要操作
char str[1005][5];
int tu[1005][1005];//记录边
int num; //最后的操作数
bool top(int n)
{
priority_queue<int, vector <int>, greater<int> >a;
int c[1004];
int i, j, top=0;
for(i=0; i<n*2; i++)
{
//        printf("%d %d\n", book[i], topo[i]);
if(book[i] && topo[i]==0)
{
a.push(i);
}
}
while(!a.empty())
{
int x=a.top();
if(x>=n)
{

int y=x-n+1;
char e[5];
sprintf(e, "R%d", y);
strcpy(str[num++], e);
}
else
{
char e[5];
sprintf(e, "C%d", x+1);
strcpy(str[num++], e);
}
a.pop();
if(x>=n)
{
for(i=0; i<n; i++)
{
if(tu[x][i]) //如果是要求发生在操作x之后
{
topo[i]--;
if(topo[i]==0)
{
a.push(i);
}
}
}
}
else
{
for(i=n; i<2*n; i++)
{
if(tu[x][i])
{
topo[i]--;
if(topo[i]==0)
{
a.push(i);
}
}
}
}

}
for(i=0; i<2*n; i++)if(topo[i])return false;
return true;
}
int main()
{
int t;
while(~scanf("%d", &t))
{
while(t--)
{
int i, j;
num=0;
memset(topo, 0, sizeof(topo));
memset(book, 0, sizeof(book));
memset(str, 0, sizeof(str));
memset(tu, 0, sizeof(tu));
memset(b, 0, sizeof(b));
int n;
cin>>n;
for(i=0; i<n; i++)scanf("%s", a[i]);
for(i=0; i<n; i++)
{
for(j=0; j<n; j++)
{
b[i][j]=a[i][j]=='X';
if(b[i][j])
{
book[i+n]=1; //记录这一行是否需要操作
}
else {
book[j]=1;  //记录这一列是否需要操作
}
}
}
for(i=0; i<n; i++)
{
for(j=0; j<n; j++)
{
if(b[i][j])
{
if(book[j]){topo[i+n]++;tu[j][i+n]=1;}//如果这个点所在列需要操作,那么这个点所在行操作应该在列操作之后
}else
{
if(book[i+n]){topo[j]++;tu[i+n][j]=1;}//如果这个点所在行需要操作,那么这个点所在列操作应该在行操作之后

}
}
}
bool ans=top(n);
if(ans==0)printf("No solution\n");
else
{
printf("%s", str[0]);
int i;
for(i=1; i<num; i++)printf(" %s", str[i]);
printf("\n");
}

}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: