题目链接: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; }