题意:
给出一个由字母边框拼起来的图,问这个图是又多少种构造方式,输出所有的方式。
分析:
如果这个字母边框中有其他的字母,则可以看成是一个这个字母到那个字母的一条边。然后用拓扑排序输出就可以了。
#include<cstdio>
#include<cstring>
using namespace std;
int h,w;
char g[35][35];
bool mp[35][35];
bool vis[35];
int ans[35];
bool flag[35];
int q[35],cnt;
void build(){
int i,j,k,l;
for(i=1;i<=h;i++){
for(j=1;j<=w;j++){
char c=g[i][j];
if(c=='.') continue;
if(!flag[c-'A']){
int c1,c2,r; //左边界,有边界,下边界。
flag[c-'A']=1;
//左边界
for(k=1;;k++){
for(l=i;l<=h;l++){
if( g[l][k]==c ){
break;
}
}
if( l<=h ) break;
}
c1=k;
//右边界
for(k=w;;k--){
for(l=i;l<=h;l++){
if(g[l][k]==c) break;
}
if(l<=h) break;
}
c2=k;
//下边界
for(k=h;;k--){
for(l=c1;l<=c2;l++){
if(g[k][l]==c) break;
}
if(l<=c2) break;
}
r=k;
//扫描边框
for(k=c1;k<=c2;k++){
int u=c-'A';
int v=g[i][k]-'A';
if(u!=v){
mp[u][v]=1;
}
v=g[r][k]-'A';
if(u!=v) mp[u][v]=1;
}
for(k=i;k<=r;k++){
int u=c-'A';
int v=g[k][c1]-'A';
if(u!=v) mp[u][v]=1;
v=g[k][c2]-'A';
if(u!=v) mp[u][v]=1;
}
}
}
}
}
void dfs(int i){
if(i==cnt){
for(int j=0;j<cnt;j++){
printf("%c",ans[j]+'A');
}
printf("\n");
return;
}
for(int j=0;j<cnt;j++){
if(vis[q[j]]) continue;
ans[i]=q[j];
bool state=true;
for(int k=i;k>0&&state;k--){
for(int l=0;l<k;l++){
if(mp[ans[k]][ans[l]]){
state=0;
break;
}
}
}
if(!state) continue;
vis[q[j]]=1;
dfs(i+1);
vis[q[j]]=0;
}
}
int main(){
while(~scanf("%d%d",&h,&w)){
for(int i=1;i<=h;i++){
scanf("%s",g[i]+1);
}
memset(mp,0,sizeof mp);
memset(flag,0,sizeof flag);
build();
cnt=0;
for(int i=0;i<26;i++){
if(flag[i]){
q[cnt++]=i;
vis[i]=0;
}
}
dfs(0);
}
return 0;
}