Frame Stacking(拓扑排序)

题目链接:http://acm.tju.edu.cn/toj/showp1076.html
1076.   Frame Stacking
Time Limit: 1.0 Seconds    Memory Limit: 65536K
Total Runs: 145    Accepted Runs: 54



Consider the following 5 picture frames placed on an 9 x 8 array.

Now place them on top of one another starting with 1 at the bottom and ending up with 5 on top. If any part of a frame covers another it hides that part of the frame below.

Viewing the stack of 5 frames we see the following.

In what order are the frames stacked from bottom to top? The answer is EDABC.

Your problem is to determine the order in which the frames are stacked from bottom to top given a picture of the stacked frames. Here are the rules:

1. The width of the frame is always exactly 1 character and the sides are never shorter than 3 characters.

2. It is possible to see at least one part of each of the four sides of a frame. A corner shows two sides.

3. The frames will be lettered with capital letters, and no two frames will be assigned the same letter.


INPUT DATA

Each input block contains the height, h (h≤30) on the first line and the width w (w≤30) on the second. A picture of the stacked frames is then given as h strings with w characters each.


Example input:

9
8
.CCC....
ECBCBB..
DCBCDB..
DCCC.B..
D.B.ABAA
D.BBBB.A
DDDDAD.A
E...AAAA
EEEEEE..

Your input may contain multiple blocks of the format described above, without any blank lines in between. All blocks in the input must be processed sequentially.


OUTPUT DATA

Write the solution to the standard output. Give the letters of the frames in the order they were stacked from bottom to top. If there are multiple possibilities for an ordering, list all such possibilities in alphabetical order, each one on a separate line. There will always be at least one legal ordering for each input block. List the output for all blocks in the input sequentially, without any blank lines (not even between blocks).


Example Output:

EDABC
题目大意:给定一个摞起来的照片图片,输出照片排放的位置,如果有多种放法的话按字典序从小到大输出所有的解
题解,这是一个很好的拓扑排序的题,题目中说了每个相片的每条边肯定会漏出至少一个字母,所以很容易确定每个相片的位置,及找到这个相片的横坐标和纵坐标的最左端和最右端,最上端,最下端的值
在处理的时候不要忘记对'.'的处理,还有从A~Z不是每个字母都会出现。
建图的时候因为这个图有很多的重边,而且边数不多的时候最好用矩阵存储,在拓扑排序的时候因为是要输出所有的解,所以使用dfs最好。
下面代码中有详细的注释
  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<string>
  5 #include<algorithm>
  6 using namespace std;
  7 #define N 110
  8 #define INF 0x1fffffff
  9 
 10 struct Node{
 11     int x1,y1,x2,y2;//x1,y1是最下和最左的点
 12     bool flag;//标记一个字母是否出现过
 13     void init(){//初始化所有点的时候找最大的时候初始化成最小,找最小的时候初始化成最大,才可以不断更新
 14         flag = 0;
 15         x1 = y1 = INF;
 16         x2 = y2 = -INF;
 17     }
 18 }node[26];
 19 int n , m;
 20 char mp[N][N];//保存一张图
 21 int g[26][26];//建立关系图
 22 int in[26];//入度
 23 int vis[26];//是否访问过
 24 void add(int u , int v)
 25 {
 26     g[u][v]=1;
 27 }
 28 int total;
 29 void dfs(int cnt , string s)
 30 {
 31     if(cnt==total) printf("%s\n",s.c_str());//dfs当已经把所有的字母顺序都访问过了后就不再进行搜索了
 32     for(int i= 0 ;i < 26 ;i++)
 33     {
 34         if(node[i].flag == 1&&!vis[i]&&in[i]==0)//注意考虑这个字母没有出现的第一个条件
 35         {
 36             vis[i]=1;
 37             for(int j = 0 ; j < 26 ; j++)
 38                 if(g[i][j]) in[j]--;
 39             char ch = i+'A';
 40             dfs(cnt+1,s+ch);//因为找所有解所以后面要还原之前操作
 41             for(int j = 0 ; j < 26 ;j++)
 42                 if(g[i][j]) in[j]++;
 43             vis[i]=0;
 44         }
 45     }
 46 }
 47                 
 48 void tuop()//拓扑排序
 49 {
 50      total = 0;
 51     for(int i = 0 ;i < 26 ; i++)
 52         vis[i] = 0,in[i] = 0;
 53     for(int i = 0 ; i < 26 ;i++)
 54         for(int j = 0 ;j < 26 ;j++)
 55             if(g[i][j]) in[j]++;
 56     for(int i = 0 ;i < 26 ;i++)
 57         total +=node[i].flag;
 58     dfs(0,"");
 59 }
 60 int main()
 61 {
 62     while(~scanf("%d%d",&n,&m))
 63     {
 64         for(int i = 0 ;i < n ; i++)
 65             scanf("%s",mp[i]);//如果挨个读入字符两重循环scanf会读入末尾的空行
 66         for(int i =0 ; i < 26; i++)
 67             node[i].init();
 68         for(int i =0 ;i < n ;i++)
 69         {
 70             for(int j = 0 ; j < m ;j++)
 71             {
 72                 if(mp[i][j]=='.') continue;
 73                 int id = mp[i][j]-'A';
 74                 node[id].flag=1;
 75                 node[id].x1 = min(node[id].x1,i);
 76                 node[id].y1 = min(node[id].y1,j);
 77                 node[id].x2 = max(node[id].x2,i);
 78                 node[id].y2 = max(node[id].y2,j);
 79             }
 80         }//找到每个字母对应的照片的位置
 81         memset(g,0,sizeof(g));
 82         for(int i = 0 ;i < 26 ;i++)
 83         {
 84             if(node[i].flag == 0) continue;
 85             int y1 = node[i].y1 , y2 = node[i].y2,x;
 86             for(x = node[i].x1;x<=node[i].x2 ;x++)
 87             {
 88                 if(mp[x][y1]!=i+'A') add(i,mp[x][y1]-'A');
 89                 if(mp[x][y2]!=i+'A') add(i,mp[x][y2]-'A');
 90             }
 91             int x1 = node[i].x1 , x2 = node[i].x2,y;
 92             for(y = node[i].y1;y<=node[i].y2 ;y++)
 93             {
 94                 if(mp[x1][y]!=i+'A') add(i,mp[x1][y]-'A');
 95                 if(mp[x2][y]!=i+'A') add(i,mp[x2][y]-'A');
 96             }
 97         }//扫描每条边并建图,如图这条边上本来应该出现同一个字母的时候出现了其他的就说明了其他的字母在这个字母的照片的上面所以建一条从下面字母到上面字母的有向边
 98         tuop();
 99     }
100     return 0;
101 }

 

 

转载于:https://www.cnblogs.com/shanyr/p/4715221.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值