POJ1128 Frame Stacking(拓扑排序)

题目链接:http://poj.org/problem?id=1128

题意:给你一个平面,里面有些矩形(由字母围成),这些矩形互相有覆盖关系,请从求出最底层的矩形到最上层的矩形的序列,如果存在多种序列,答案按照字典序依次输出。

思路:这道题的难点在建图,利用矩形之间的覆盖关系建图,说着容易,实际上仔细想想不太容易。由于矩形的任意一个边界不会完全被覆盖,所以我们可以确定一个矩形的上下左右边界,然后对每个矩形的上下左右边界扫一遍,看是否被其他字母所覆盖,利用覆盖关系建图。这里无法利用队列的方式拓扑排序,因为要输出所有的序列,所以dfs的方式更为出色,具体的注释都写在代码里面了。

 

//Author: xiaowuga
#include <iostream>
#include <algorithm>
#include <set>
#include <vector>
#include <queue>
#include <cmath>
#include <cstring>
#include <cstdio>
#include <ctime>
#include <map>
#include <bitset>
#include <cctype>
#define maxx INT_MAX
#define minn INT_MIN
#define inf 0x3f3f3f3f
#define mem(s,ch) memset(s,ch,sizeof(s))
#define da cout<<"da"<<endl
#define uoutput(a,i,l,r) for(int i=l;i<r;i++) if(i==l) cout<<a[i];else cout<<" "<<a[i];cout<<endl;
#define doutput(a,i,l,r) for(int i=r-1;i>=0;i--) if(i==r-1) cout<<a[i];else cout<<" "<<a[i];cout<<endl;
const long long N=35;
using namespace std;
typedef long long LL;
int L[N],R[N],U[N],D[N],in[N],vis[N],v[N];
//L左边界数组,R有边界数组,U上边界数组,D下边界数组
//vis字母存在数组,v是dfs中是否访问数组
char pic[N][N],ans[N];
int p[N][N];
int n,m,ct;
//初始化
void init(){
    ct=0;//存在字母总数量初始化为0
    mem(in,0);//入度数组初始化为0
    mem(vis,0);//字母存在数组初始化为0
    mem(v,0);
    mem(p,0);//邻接矩阵初始化为0
    //上左边界最大化,下右边界最小化
    mem(L,inf);mem(U,inf);mem(R,-1);mem(D,-1);
}
void make_g(int i,int j,int k){
    int t=pic[i][j]-'A';
    if(k!=t){
        if(!p[k][t]) {p[k][t]=1;in[t]++;}
    }
}
void dfs(int x,int y){
    ans[y]=x+'A';
    v[x]=1;//标记为访问过
    if(y==ct){//全部字母已经排好拓扑序
        for(int i=1;i<=ct;i++) cout<<ans[i];cout<<endl;//输出
        v[x]=0;//恢复
        return ;
    }
    int q[N],num=0;
    //i从0-26保证了字典序
    for(int i=0;i<26;i++){
        if(p[x][i]) --in[i];//存在连接则连接减少入度
        if(vis[i]&&!in[i]&&!v[i]) q[num++]=i;//存在连接且入度减为0,且未访问
    }
    //对所有后续节点进行dfs
    for(int i=0;i<num;++i) dfs(q[i],y+1);
    for(int i=0;i<26;i++) if(p[x][i]) in[i]++;//恢复
    v[x]=0;//恢复
}
void topo(){
    for(int i=0;i<26;++i) if(vis[i]&&!in[i]) dfs(i,1);
}
int main() {
    ios::sync_with_stdio(false);cin.tie(0);
    while(cin>>n>>m){
        init();
        //输入整个图形并确定每个矩形的上下左右边界
        for(int i=0;i<n;++i) for(int j=0;j<m;++j){
            cin>>pic[i][j];
            if(pic[i][j]!='.'){
                int t=pic[i][j]-'A';
                if(!vis[t]){ vis[t]=1;ct++;}
                L[t]=min(L[t],j);
                R[t]=max(R[t],j);
                U[t]=min(U[t],i);
                D[t]=max(D[t],i);
            }
        }
        for(int k=0;k<26;k++){
           if(vis[k]){
                int i,j;
                i=U[k];//上边界上
                for(j=L[k];j<=R[k];j++) make_g(i,j,k);
                i=D[k];//下边界上
                for(j=L[k];j<=R[k];j++) make_g(i,j,k);
                j=L[k];//左边界上
                for(i=U[k]+1;i<D[k];i++) make_g(i,j,k);
                j=R[k];//右边界上
                for(i=U[k]+1;i<D[k];i++) make_g(i,j,k);
           } 
        }
        topo(); 
    } 
    return 0;
}
View Code

 

posted on 2017-07-24 23:22  xiaowuga  阅读(166)  评论(0编辑  收藏  举报

导航