poj1128 Frame Stacking

Frame Stacking
Time Limit: 1000MS Memory Limit: 10000K
Total Submissions: 3636 Accepted: 1204

Description

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

EEEEEE.. ........ ........ ..BBBB.. .C.C....

E....E.. DDDDDD.. ........ ..B..B.. .C.C....

E....E.. D....D.. ........ ..B..B.. .CCC....

E....E.. D....D.. ....AAAA ..B..B.. ........

E....E.. D....D.. ....A..A ..BBBB.. ........

E....E.. DDDDDD.. ....A..A ........ ........

E....E.. ........ ....AAAA ........ ........

EEEEEE.. ........ ........ ........ ........

    1        2        3        4        5   

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.
.CCC....

ECBCBB..

DCBCDB..

DCCC.B..

D.B.ABAA

D.BBBB.A

DDDDAD.A

E...AAAA

EEEEEE..






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

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.
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

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).

Sample Input

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

Sample Output

EDABC
 
     這題和上一篇博客的那道題的做法差不多,就是建圖比較麻煩。還有題目保證至少存在一種符合要求的序列,當有多種情況時按字典序由小到大輸出所有的情況。
     這題的難點是輸出所有的拓撲序列,根據題目描述最壞情況有26!中情況(即每一個圖片都無重疊部分),剛開始就被它給嚇着了,遲遲不敢下手!最後無奈之下暴力的試了一下竟然過了。只能說這題數據太水了,不過話說如果不是這樣的話,這題我還真不知道怎麼解了,畢竟按照暴力的方法時間複雜度太高了(歡迎哪位大神來分享下較好的算法)。
     對於建圖,如果不懂的話,可以參照我的上一篇博客,然後最後求拓撲序列就是直接枚舉全排列了。對於每一種排列,如果每條邊都是從左到右則符合。這題其實也沒用求拓撲的算法,主要是根據它的定義做個判斷。
#include<iostream>
#include<cstdio>
#include<cstring>

using namespace std;
int w,h;
char image[35][35];
int map[35][35];//鄰接表
int flag[26];//記錄字母是否出現過
int q[30],cnt;//出現的字母(由小到大)
int visit[30];//dfs時的標記數組
int ans[30];//序列

void build()
{
    int i,j,k,l;
    for(i=1;i<=h;i++)
        for(j=1;j<=w;j++)
        {
            char c=image[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(image[l][k]==c)
                            break;
                    if(l<=h)
                        break;
                }
                c1=k;
                //右邊界
                for(k=w;;k--)
                {
                    for(l=i;l<=h;l++)
                        if(image[l][k]==c)
                            break;
                    if(l<=h)
                        break;
                }
                c2=k;
                //下邊界
                for(k=h;;k--)
                {
                    for(l=c1;l<=c2;l++)
                        if(image[k][l]==c)
                            break;
                    if(l<=c2)
                        break;
                }
                r=k;
                //開始掃描框架上的元素
                for(k=c1;k<=c2;k++)
                {
                    int u=c-'A';
                    int v=image[i][k]-'A';
                    if(u!=v)
                        map[u][v]=1;
                    v=image[r][k]-'A';
                    if(u!=v)
                        map[u][v]=1;
                }
                for(k=i;k<=r;k++)
                {
                    int u=c-'A';
                    int v=image[k][c1]-'A';
                    if(u!=v)
                        map[u][v]=1;
                    v=image[k][c2]-'A';
                    if(u!=v)
                        map[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(!visit[q[j]])
        {
            ans[i]=q[j];
            bool state=true;
            for(int k=i;k>0&&state;k--)
                for(int l=0;l<k;l++)
                    if(map[ans[k]][ans[l]])
                    {
                        state=false;
                        break;
                    }
            if(!state)
                continue;
            visit[q[j]]=1;
            dfs(i+1);
            visit[q[j]]=0;
        }
}

int main()
{
    int i,j;
    while(~scanf("%d%d",&h,&w))
    {
        for(i=1;i<=h;i++)
        {
            getchar();
            for(j=1;j<=w;j++)
                image[i][j]=getchar();
        }
        memset(map,0,sizeof(map));
        memset(flag,0,sizeof(flag));
        build();//建圖
        cnt=0;
        for(i=0;i<26;i++)
            if(flag[i])
            {
                q[cnt++]=i;
                visit[i]=0;
            }
        dfs(0);//枚舉
    }
    return 0;
}

發佈了117 篇原創文章 · 獲贊 45 · 訪問量 17萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章