https://www.luogu.org/problemnew/show/P2741
这题整体难度不大,但有很多细的东西,所以容易错。
1.读入矩阵
2.求出有多少个图像(即矩阵中有多少种不同的字母),并从小到大排序
3.t表示有几张图像,从1~t枚举出压在第i张图像上面的图像(x),构成拓扑结构,即i是x的入度,必须有i才有x
4.做一遍dfs,搜出所有的可能:
①枚举当前没有入度的节点(代码中是f[i]==0),将它加入答案,标记已使用
②将以i为入度的点的f减一,
③重复①,②
还有,如果在洛谷提交的话,请不要开O2优化,会莫名其妙的WA一个点的。
代码上有注释,易懂:
#include <bits/stdc++.h>
#define INF 100
using namespace std ;
char a[31][31],x[31] ;//x代表 第i号是字母c
int y['Z'] ; // 字母c是第i号
int t=0 ;//有几个不同的字母
int f[31] ;//图像i下面压着多少个图像
int sum[31] ;//表示i上面压着几张图片。拓扑排序后面好删
int b[31][31] ;//表示i上面压的第j张图像是x
char ans[100] ;//一个答案串
int vis[31] ;//当前字母是否在搜索中已经出现过
int h[31][31] ;//表示i上面是否已经搜索到j在i上面
int n,m ;
int hash['Z'] ;
void dfs(int k,int val)
{
if (k==t) //已经枚举过了t个图像
{
for (int i=1;i<=t;i++) printf("%c",ans[i]) ;
printf("\n") ;
return ;
}
for (int i=1;i<=t;i++)
{
if (f[i]==0 && !vis[i]) //入度为0 且没有访问过
{
vis[i]=1 ;
ans[k+1]=x[i] ;
for (int j=1;j<=sum[i];j++)
f[b[i][j]]-- ;
dfs(k+1,i) ;//dfs(i,j)表示刚刚定下第j个位置放i
for (int j=1;j<=sum[i];j++)
f[b[i][j]]++ ;
vis[i]=0 ;
}
}
//题目已保证读入数据合法,不用担心没有答案
return ;
}
int main()
{
scanf("%d%d",&n,&m) ;
for(int i=0;i<n;i++) //读入矩阵
{
scanf("\n");
for(int j=0;j<m;j++)
{
scanf("%c",&a[i][j]);
}
}
for (int i=0;i<n;i++)
for (int j=0;j<m;j++){
char c=a[i][j] ;
if (!hash[c] && isalpha(c)){ //当前字母新出现
x[++t]=c ;//x 第i号是字母c
hash[c]++ ;
}
}
for (int i=1;i<=t;i++) //排成字典序
for (int j=i+1;j<=t;j++)
if (x[i]>x[j]){
char tmp=x[i];x[i]=x[j];x[j]=tmp ;
}
for (int i=1;i<=t;i++) //字母c是第i号
{
y[x[i]]=i ;
}
for (int k=1;k<=t;k++) //枚举t张图
{
int minx=INF,maxx=-INF,miny=INF,maxy=-INF ;
for (int i=0;i<n;i++) //图像的位置,只需要知道minx,maxx,miny,maxy
for (int j=0;j<m;j++){
if (a[i][j]==x[k]){
minx=min(minx,i);miny=min(miny,j);
maxx=max(maxx,i);maxy=max(maxy,j);
}
}
int i=maxx ;
for (int j=miny+1;j<=maxy-1;j++){
if (a[i][j]!=x[k] && !h[k][y[a[i][j]]]){ //B向A连边
b[k][++sum[k]]=y[a[i][j]];//拓扑排序,表示图像b(a[i][j])的下面有图像a(x[k])
f[y[a[i][j]]]++; //图像b的前+1
h[k][y[a[i][j]]]=1 ;//判重
}
}
i=minx ;
for (int j=miny+1;j<=maxy-1;j++){
if (a[i][j]!=x[k] && !h[k][y[a[i][j]]]){
b[k][++sum[k]]=y[a[i][j]];
h[k][y[a[i][j]]]=1 ;
f[y[a[i][j]]]++;
}
}
int j=maxy ;
for (int i=minx;i<=maxx;i++){
if (a[i][j]!=x[k] && !h[k][y[a[i][j]]]){
b[k][++sum[k]]=y[a[i][j]];
f[y[a[i][j]]]++;
h[k][y[a[i][j]]]=1 ;
}
}
j=miny ;
for (int i=minx;i<=maxx;i++){
if (a[i][j]!=x[k] && !h[k][y[a[i][j]]]){
b[k][++sum[k]]=y[a[i][j]];
f[y[a[i][j]]]++;
h[k][y[a[i][j]]]=1 ;
}
}
}
for (int i=1;i<=t;i++)
if (f[i]==0) //入度为0的点
{
vis[i]=1;
ans[1]=x[i] ;
for (int j=1;j<=sum[i];j++)
f[b[i][j]]-- ;
dfs(1,i) ;//dfs(i,j)表示刚刚定下第j个位置放i
for (int j=1;j<=sum[i];j++) //清标记
f[b[i][j]]++ ;
vis[i]=0 ;
}
return 0 ;
}