zoj 3780(拓扑排序)

本文探讨了如何解决在黑白棋盘上涂色的问题,通过活动拓扑排序找到无环涂色方案,确保字典序最小。文章详细介绍了算法实现步骤及关键逻辑。

题意:

有一个N’N的板,刚开始板上的所有元素都是其他颜色(不是黑,也不是白),且涂得方法有两种。

1、涂一行,使该行的所有元素都变成黑色。

2.、涂一列,是该列的所有元素都变成白色。


解题思路:

我们先考虑一下两种情况,就是有一行上得元素存在白点;有一列上得元素存在黑点。

对于第一种情况,我们是否可以得到该行肯定事先涂黑的,然后在出现白点的列上,涂白,使得该行所对应列的位置存在白点。

对于第二种情况,同第一种情况。

所以我们可以把涂某一行或涂某一列看成是活动,且凃行的活动与凃列的活动之间存在明显的先后关系,所以我们可以见图,然后利用拓扑排序判断涂有无环,并再无环的条件下来算出方案。


注意:

这里需要字典序最小,所以要用优先队列



#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <vector>
#include <algorithm>
#include <queue>
using namespace std;
#define MAXN0 510
char map[MAXN0][MAXN0];
bool flagX[MAXN0],flagO[MAXN0];
vector<int>G[MAXN0<<1];
int ct[MAXN0<<1],ans[MAXN0<<1],cnt;
int N;
void init(){
    int up = N<<1;
    cnt = 0;
    for(int i=1;i<=up;++i){
        if(G[i].size()){
            G[i].clear();
        }
        ct[i] = 0;
    }
    memset(flagX,false,sizeof(flagX));
    memset(flagO,false,sizeof(flagO));
}
void solve(){
    int up = N<<1;
    priority_queue<int,vector<int>,greater<int> >pq;
    for(int i=1;i<=up;++i){
        if(!ct[i]){
            if(G[i].size())
                pq.push(i);
        }
    }
    int st,to,sz;
    while(!pq.empty()){
        st = pq.top();
        ans[cnt++] = st;
        pq.pop();
        sz = (int)G[st].size();
        for(int i=0;i<sz;++i){
            to = G[st][i];
            --ct[to];
            if(!ct[to]){
                pq.push(to);
            }
        }
    }
    for(int i=1;i<=up;++i){
        if(ct[i]){
            printf("No solution\n");
            return;
        }
    }
    if(ans[0]>=1&&ans[0]<=N){
        printf("C%d",ans[0]);
    }
    else{
        printf("R%d",ans[0]-N);
    }
    for(int i=1;i<cnt;++i){
        if(ans[i]>=1&&ans[i]<=N){
            printf(" C%d",ans[i]);
        }
        else{
            printf(" R%d",ans[i]-N);
        }
    }
    puts("");
    
}
int main(){
    int T;
    while(scanf("%d",&T)!=EOF){
        while(T--){
            init();
            scanf("%d",&N);
            for(int i=1;i<=N;++i){
                scanf("%s",map[i]+1);
                for(int j=1;j<=N;++j){
                    if(map[i][j]=='X'){
                        flagX[i] = true;
                    }
                    else {
                        flagO[j] = true;
                    }
                }
            }
            for(int i=1;i<=N;++i){
                if(flagX[i]){
                    for(int j=1;j<=N;++j){
                        if(map[i][j]=='O'){
                            G[N+i].push_back(j);
                            ++ct[j];
                        }
                    }
                }
                if(flagO[i]){
                    for(int j=1;j<=N;++j){
                        if(map[j][i]=='X'){
                            G[i].push_back(j+N);
                            ++ct[j+N];
                        }
                    }
                }
            }
            solve();
        }
        
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值