ZOJ 3780 Paint the Grid Again(拓撲排序)


ZOJ 3780 Paint the Grid Again

Leo has a grid with N × N cells. He wants to paint each cell with a specific color (either black or white).
Leo has a magical brush which can paint any row with black color, or any column with white color. Each time he uses the brush, the previous color of cells will be covered by the new color. Since the magic of the brush is limited, each row and each column can only be painted at most once. The cells were painted in some other color (neither black nor white) initially.
Please write a program to find out the way to paint the grid.
Input
There are multiple test cases. The first line of input contains an integer T indicating the number of test cases. For each test case:
The first line contains an integer N (1 <= N <= 500). Then N lines follow. Each line contains a string with N characters. Each character is either 'X' (black) or 'O' (white) indicates the color of the cells should be painted to, after Leo finished his painting.
Output
For each test case, output "No solution" if it is impossible to find a way to paint the grid.
Otherwise, output the solution with minimum number of painting operations. Each operation is either "R#" (paint in a row) or "C#" (paint in a column), "#" is the index (1-based) of the row/column. Use exactly one space to separate each operation.
Among all possible solutions, you should choose the lexicographically smallest one. A solution X is lexicographically smaller than Y if there exists an integer k, the first k - 1 operations of X and Y are the same. The k-th operation of X is smaller than the k-th in Y. The operation in a column is always smaller than the operation in a row. If two operations have the same type, the one with smaller index of row/column is the lexicographically smaller one.
Sample Input
2
2
XX
OX
2
XO
OX
Sample Output
R2 C1 R1
No solution

題意:一次塗色能把一行塗成X,或把一列塗成O,在用最少次數塗色的前提下,輸出字典序最小的塗色方案(列塗色比行塗色小,塗色下標小的較小)。

這題和那道用拓撲排序做的框架堆疊很像,但我當時沒認真想那道題…造成了面對這道題的無力…這個故事告訴我們不要放過到手邊的題,不然會后悔。

突破點在於:根據當前的塗色狀態,是可以反推上一個塗色狀態的。對於在i行、j列,當前狀態為X的格子,我們可以想到,對於i行的塗色必定發生在對於j列的塗色之后。

也就是說,可以推出若干組塗色的兩兩相對順序。

因此,將各種塗色情況設為點,從Cj向Ri引有向邊(先發生的塗色->后發生的塗色),對於這個有向圖求出的拓撲序列就可以滿足最終達到輸入塗色狀態的要求。

並且,考慮到輸出的是字典序最小方案,將列塗色設為前N個點,行塗色設為后N個點,用輸出最小值的優先隊列來存儲每次的零入度點。

可以想到,類似的可以用拓撲排序解決的問題都隱含着某種狀態具有先后關系的條件。

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<queue>
#include <functional>
#define maxn 550
using namespace std;
int head[2*maxn];
typedef struct{
    int to,next;
}e;
e edge[maxn*maxn];
//1-N為C操作,N-2N為R操作
int N,cnt,iq;
char maze[maxn][maxn];
int queues[2*maxn];
int degree[2*maxn];
bool vis[2*maxn];
void init(){
    cnt=0;
    iq=0;
    memset(head,-1,sizeof(head));
    memset(degree,0,sizeof(degree));
    memset(vis,false,sizeof(vis));
}
int addedge(int x,int y){
    edge[cnt].to=y;
    edge[cnt].next=head[x];
    head[x]=cnt;
    cnt++;
    return 0;
}
int solve(){
    int i,k,s;
    priority_queue<int, vector<int>, greater<int> > P;
    for(i=1;i<=2*N;i++){
        if(!degree[i]){
            P.push(i);
        }
    }
    while(!P.empty()){
        s=P.top();
        P.pop();
        queues[iq++]=s;
        for(k=head[s];k!=-1;k=edge[k].next){
            if(!--degree[edge[k].to]){
                P.push(edge[k].to);
            }
        }
    }
    return 0;
}
int main(){
    int T,i,j,k;
    scanf("%d",&T);
    while(T--){
        init();
        scanf("%d",&N);
        for(i=1;i<=N;i++){
            scanf("%s",maze[i]+1);
        }
        for(i=1;i<=N;i++){
            for(j=1;j<=N;j++){
                if(maze[i][j]=='X'){
                    addedge(j,i+N);
                    vis[i+N]=true;
                    degree[i+N]++;
                }
                if(maze[i][j]=='O'){
                    addedge(i+N,j);
                    vis[j]=true;
                    degree[j]++;
                }
            }
        }
        solve();
        if(iq!=N*2){
            printf("No solution\n");
            continue;
        }
        for(i=0;i<iq;i++){
            if(!vis[queues[i]])
                continue;
            if(queues[i]<=N){
                printf("C");
                printf("%d",queues[i]);
            }
            else{
                printf("R");
                printf("%d",queues[i]-N);
            }
            if(i<iq-1)
                printf(" ");
            else
                printf("\n");
        }
    }
    return 0;
}


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2020 ITdaan.com