您的位置:首页 > 其它

poj 1128 Frame Stacking(DFS+拓扑排序)

2017-07-21 11:49 288 查看

Frame Stacking

题目链接:哈哈,在这里

题意:每个图片由同一字母组成的边框表示,每个图片的字母都不同;

   在一个最多30*30的区域放置这些边框,这些边框叠在一起,给出从上向下看的图。每个相框保证四条边上至少有一点出现。

求底层向顶层叠放的边框次序,多种结果按字典序输出

思路:先根据原始图,对每个字母的图片建立大致轮廓(记录左上和右下)

然后根据每个图片的轮廓建一个有向无环图,被覆盖的图片向覆盖它的图片建边

最后进行dfs形式的拓扑排序,从小到大遍历(字典序)。

代码:

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;

struct Node
{
int v,next;
} E[10000];
struct Coordinate
{
int x,y;
} L[30][2];//记录每个字母的左上角和右下角

int first[30],vis[30],in[30],inq[30][30];
char mp[30][30],ans[30];
int len,Totalnum,n,m;

void add_edge(int u,int v)//邻接表存边
{
E[len].v=v,E[len].next=first[u],first[u]=len++;
}

void Record()
{
memset(in,0,sizeof(in));
memset(vis,0,sizeof(vis));
memset(inq,0,sizeof(inq));
memset(first,-1,sizeof(first));
len=0,Totalnum=0;
for(int i=0; i<26; ++i)
{
L[i][0].x=100,L[i][0].y=100;
L[i][1].x=-1,L[i][1].y=-1;
}
for(int i=0; i<n; ++i)
scanf("%s",mp[i]);
for(int i=0; i<n; ++i)//寻找每个字母的左上角和右下角
{
for(int j=0; j<m; ++j)
{
if(mp[i][j]=='.')
continue;
int val=mp[i][j]-'A';
if(!vis[val])
vis[val]=1,++Totalnum;
L[val][0].x=min(L[val][0].x,i);
L[val][0].y=min(L[val][0].y,j);
L[val][1].x=max(L[val][1].x,i);
L[val][1].y=max(L[val][1].y,j);
}
}
}

void Build()//建图
{
for(int i=0; i<26; ++i)
{
if(!vis[i])
continue;
for(int k=L[i][0].x; k<=L[i][1].x; ++k)
{
if(k==L[i][0].x||k==L[i][1].x)//第一行或者是最后一行需要遍历整个列
{
for(int j=L[i][0].y; j<=L[i][1].y; ++j)
{
if(mp[k][j]=='.')
continue;
int val=mp[k][j]-'A';
if(val!=i&&!inq[i][val])//防止重边
{
inq[i][val]=1;
add_edge(i,val);
++in[val];
}
}
}
else//否则只需遍历最小列和最大列
{
if(mp[k][L[i][0].y]!='.')
{
int val=mp[k][L[i][0].y]-'A';
if(val!=i&&!inq[i][val])
{
inq[i][val]=1;
add_edge(i,val);
++in[val];
}
}
if(mp[k][L[i][1].y]!='.')
{
int val=mp[k][L[i][1].y]-'A';
if(val!=i&&!inq[i][val])
{
inq[i][val]=1;
add_edge(i,val);
++in[val];
}
}
}
}
}
}

void DFS(int len)//dfs进行拓扑排序
{
if(len==Totalnum)
{
ans[len]='\0';
printf("%s\n",ans);
return ;
}
for(int i=0; i<26; ++i)//从小到大字典序
{
if(!vis[i])
continue;
if(!in[i])//入度为0,则说明此点此时在最前面
{
--in[i];
ans[len]=i+'A';
for(int j=first[i]; ~j; j=E[j].next)//它指向的点的入度-1
--in[E[j].v];
DFS(len+1);
for(int j=first[i]; ~j; j=E[j].next)
++in[E[j].v];
++in[i];
}
}
}

int main()
{
while(~scanf("%d%d",&n,&m))
{
Record();
Build();
DFS(0);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: