POJ 1128 Frame Stacking(拓扑排序+dfs)

256 篇文章 0 订阅
125 篇文章 0 订阅

Description
每张图片上面画了一些边框,给出这些边框叠在一起后的图片,图片边框一定是由一个字母表示并且每条边至少三个字符,输入保证至少会给出边框每条边的一个字母,一个角的一个字符表示两条边,图片边框用大写字母表示,并且不会有两张图片的边框使用同一个大写字母,求从下往上的重叠顺序,如果有多种结果的话就按照字典序输出所有结果
Input
首先为两个整数n和m表示矩阵行列数,之后为一n*m矩阵表示叠加后的矩阵(1<=n,m<=30)
Output
求从下往上的重叠顺序,如果有多种结果的话就按照字典序输出所有结果
Sample Input
这里写图片描述
Sample Output
EDABC
Solution
对于每个边框i我们可以很容易的找到其边界(即两条横边两条纵边),那么在其边界上如果存在一个不是该边框的字母j,那么说明j覆盖了i,这样就得到了这些边框的上下关系,那么这个问题就可以用拓扑排序来解决,如果j覆盖了i,那么就从j往i建一条边,建完图后深搜求出所有的拓扑序列即可
Code

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
#define maxn 33
int n,m,in[maxn],flag[maxn],cnt,M[maxn][maxn];
char p[maxn][maxn],ans[maxn];
void init()
{
    cnt=0;
    memset(M,0,sizeof(M));
    memset(in,0,sizeof(in));
    memset(flag,0,sizeof(flag));
}
void dfs(int num)
{
    if(num==cnt)
    {
        ans[num]='\0';
        printf("%s\n",ans);
        return ;
    }
    for(int i=0;i<26;i++)
        if(in[i]==0&&flag[i])
        {
            ans[num]=i+'A';
            in[i]=-1;
            for(int j=0;j<26;j++)
                if(M[i][j])in[j]--;
            dfs(num+1);
            in[i]=0;
            for(int j=0;j<26;j++)
                if(M[i][j])in[j]++;
        }
}
int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        init();
        for(int i=0;i<n;i++)scanf("%s",p[i]);
        for(int k=0;k<26;k++)
        {
            int x1=maxn,y1=maxn,x2=-1,y2=-1;
            for(int i=0;i<n;i++)
                for(int j=0;j<m;j++)
                    if(p[i][j]=='A'+k)
                        x1=min(x1,i),y1=min(y1,j),x2=max(x2,i),y2=max(y2,j);
            if(x1==maxn||y1==maxn||x2==-1||y2==-1)continue; 
            flag[k]=1;cnt++;
            for(int i=x1;i<=x2;i++)
                for(int j=y1;j<=y2;j++)
                    if(i==x1||i==x2||j==y1||j==y2)
                        if(p[i][j]!='A'+k&&p[i][j]!='.')
                        {
                            int t=p[i][j]-'A';
                            if(!M[k][t])in[t]++,M[k][t]=1;
                        }
        }
        dfs(0);
    }
    return 0;
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值