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,我在数字转字符串的时候数组开小了,坑了我好久。
代码:
给定一块正方形区域,大小为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; }
相关文章推荐
- 拓扑排序(ZOJ 3780,Paint the Grid Again)
- ZOJ 3780 Paint the Grid Again 拓扑排序 策略题
- 【ZOJ 3780】Paint the Grid Again —— 模拟拓扑排序
- ZOJ-3780-Paint the Grid Again【11th浙江省赛】
- ZOJ 3780 Paint the Grid Again-贪心模拟/拓扑排序
- ZOJ - 3780-Paint the Grid Again-(拓扑排序)
- 【ZOJ - 3780】 Paint the Grid Again (拓扑排序)
- zoj 3780 Paint the Grid Again(拓扑排序)
- ZOJ 3780 Paint the Grid Again(拓扑排序)
- ZOJ 3780 - Paint the Grid Again
- ZOJ - 3780 - Paint the Grid Again
- zoj 3780 Paint the Grid Again
- ZOJ 3780 Paint the Grid Again (逆推)
- zoj 3780 Paint the Grid Again
- ZOJ 3780 Paint the Grid Again 模拟
- ZOJ 3780 Paint the Grid Again
- ZOJ 3780 Paint the Grid Again (模拟)
- Paint the Grid Again ZOJ - 3780
- 2017省组队训练 zoj3780 Paint the Grid Again (模拟)
- ZOJ 3780 Paint the Grid Again