Southern African 2001 框架折叠 (拓扑序列的应用)

题目:
考虑五个图片堆叠在一起,比如下面的9 * 8 的矩阵表示的是这些图片的边缘框。

现在上面的图片顺序为图片1放在最底下,5放在最顶上。如果任何图片的边框覆盖了其他图片的边框,被覆盖的部分不会被显示出来。

下面是一个栗子:

那么从低向上图片的堆叠顺序为 EDABC,现在的问题是给出一个堆叠后的表示,要确定从低向上的图片的堆叠顺序。

下面是判定规则:

1、图片一定是由一个字母表示并且每条边至少三个字符

2、题目保证至少会给出每条边的一个字母,一个角的一个字符代表两条边

3、图片边框用大写字母表示,并且不会有俩张图片的边框使用同一个大写字母

输入:

高度h 、宽度w、接下来是一个h * w 的矩阵,输入数据可能包括多组,中间没有空行

输出:

输出自底向上形成输入状况的图片边框所对应的字母。如果有多组排列方式,将所有的序列按照字母序排列输出。每个可行的序列战一行,对于每个输入确保至少有一个合法的序列满足题意。两组数据之间没有空格。

解题思路:

  首先由于题目中的第二个条件,所以就可以把每个图片的四个角的坐标找到,但是其实只要俩个对角的坐标就可以确定这个图片的位置了,所以只需要找到每个图片的俩个对角的坐标就行了,然后就需要对图再进行一次遍历,如果在应该出现A的地方出现了B那么说明B应该在A的上面,即B覆盖了A。然后就可以把图片边框之间的上下层次关系确定下来,之后就可以利用到拓扑排序了,如果A在B下面,那么我们就认为 Va --> Vb 有一条有向边,根据实际情况建立起来的图就是一个有向无环图,所以这个图上所有的拓扑序列就是答案。

代码:

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

const int MAXN = 26; //最多26个字母
char Gra[MAXN][MAXN];//存储初始图
int head[MAXN + 7];//用链式前向星存建立起来的图中
int flag[MAXN + 7][MAXN + 7];//flag[i][j]用于判断i 和 j 之间是否有边,用于忽略掉重复边
int h, w;//高h , 宽 w
int N; //图中一共有 N 个点
int e;  //图中一共有 e 条边

struct Map{ //把初始图先转为u v 之间存在的边,再转为链式前向星
    int u;
    int v;
}map[MAXN * MAXN + 7]; 

typedef struct EdgeNode{//链式前向星
    int to;
    int next;
}edgeNode;
edgeNode Edges[MAXN * MAXN + 7];

typedef struct Point{//坐标
    int x;
    int y;
}point;

typedef struct Photo{//照片的位置
    point leftUp;//左上角
    point rightDown;//右下角
}photos;
photos pht[MAXN + 7];

int getN()//由初始图获得节点的个数
{
    int has[27] ={0};
    for(int i = 1; i <= h; i++)
        for(int j = 1; j <= w; j++)
            if(Gra[i][j] != ‘.‘)
                has[ Gra[i][j] - ‘A‘ ]++;
    int n = 0;
    for(int i = 0; i <= 26; i++)
        if(has[i] != 0)
            n++;
    return n;
}

void getXY()//由初始图获得每个照片的两个对角坐标
{
    for(int i = 1; i <= h; i++)
    {
        for(int j = 1; j <= w; j++)
        {
            for(int k = 1; k <= N; k++)
            {
                if(Gra[i][j] != ‘.‘ && Gra[i][j] == k + ‘A‘ - 1)
                {
                    //cout << "*" << i << " " << j <<"*"<<endl;
                    pht[k].leftUp.x = min( pht[k].leftUp.x, i);
                    pht[k].leftUp.y = min( pht[k].leftUp.y, j);
                    pht[k].rightDown.x = max( pht[k].rightDown.x, i);
                    pht[k].rightDown.y = max( pht[k].rightDown.y, j);
                }
            }
        }
    }
}

void initPht()//初始化对角坐标
{
    for(int i = 0; i <= N; i++)
    {
        pht[i].leftUp.x = h + 1;
        pht[i].leftUp.y = w + 1;
        pht[i].rightDown.x = -1;
        pht[i].rightDown.y = -1;
    }
}

void buidEdge(photos pht, int m)//由初始图建立起来的一个基本图
{
    int go;
    go = pht.leftUp.y;
    //cout << pht.leftUp.x << " " << pht.leftUp.y<<"     " << pht.rightDown.x <<" "<< pht.rightDown.y<<endl;
    while( go <= pht.rightDown.y)//横向遍历
    {
        //如果不是‘.‘,且不是本身,且之间尚未有边那么就建立起边
        if( Gra[pht.leftUp.x][go] != ‘.‘ && Gra[pht.leftUp.x][go] != m + ‘A‘ - 1 && flag[Gra[pht.leftUp.x][go] - ‘A‘ + 1][m] != 1)
        {
            //cout << pht.leftUp.x << " ^ " << go << endl;
            ++e;
            flag[Gra[pht.leftUp.x][go] - ‘A‘ + 1][m] = 1;
            map[e].v = Gra[pht.leftUp.x][go] - ‘A‘ + 1;
            map[e].u = m;
        }
        if( Gra[pht.rightDown.x][go] != ‘.‘ && Gra[pht.rightDown.x][go] != m + ‘A‘ - 1 && flag[Gra[ pht.rightDown.x][go] - ‘A‘ + 1][m] != 1)
        {
            ++e;
            flag[Gra[ pht.rightDown.x][go] - ‘A‘ + 1][m] = 1;
            map[e].v = Gra[pht.rightDown.x][go] - ‘A‘ + 1;
            map[e].u = m;
        }
        go++;
    }
    go = pht.leftUp.x;
    while( go <= pht.rightDown.x)//纵向遍历
    {
        if( Gra[go][pht.rightDown.y] != ‘.‘ && Gra[go][pht.rightDown.y] != m + ‘A‘ - 1 && flag[Gra[go][pht.rightDown.y] - ‘A‘ + 1][m] != 1)
        {
            ++e;
            flag[Gra[go][pht.rightDown.y] - ‘A‘ + 1][m] = 1;
            map[e].v = Gra[go][pht.rightDown.y] - ‘A‘ + 1;
            map[e].u = m;
        }
        if( Gra[go][pht.leftUp.y] != ‘.‘ && Gra[go][pht.leftUp.y] != m + ‘A‘ - 1 && flag[Gra[go][pht.leftUp.y] - ‘A‘ + 1][m] != 1)
        {
            ++e;
            flag[Gra[go][pht.leftUp.y] - ‘A‘ + 1][m] = 1;
            map[e].v = Gra[go][pht.leftUp.y] - ‘A‘ + 1;
            map[e].u = m;
        }
        go++;
    }
}

int vis[MAXN + 7];
int indegree[MAXN + 7];

void getIdg(int vis[])//获得每个点的入度
{
    memset(indegree, 0, sizeof(indegree));
    for(int i = 1;i <= N; i++)
    {
        if(!vis[i])
        {
            for(int j = head[i]; j != -1; j = Edges[j].next)
            {
                indegree[Edges[j].to ] ++;
            }
        }
    }
}

int allVis()//每个点都被删了
{
    for(int i = 1; i <= N; i++)
        if(!vis[i])return 0;
    return 1;
}

void DFS(int head[], int vis[], queue<int> Qu)
{
    queue<int> q;
    getIdg(vis);
    for(int i = 1; i <= N; i++) //每次把入度为 0 的点入到队列中
    if(!vis[i] && !indegree[i]) q.push(i);
    while(!q.empty())
    {
        int v = q.front();
        q.pop();
        queue<int> cpyQu(Qu);//复制Qu的副本并把 点 v 加入到Qu的副本中
        cpyQu.push(v);
        vis[v] = 1;        //删除已被访问到的点
        int t = head[v];
        head[v] = 1;    //删除从这个点出发的全部有向边
        if(allVis())    //如果图为空
        {
            while(!cpyQu.empty())
            {
                cout <<(char) (cpyQu.front() + ‘A‘ - 1) ;
                cpyQu.pop();
            }
            cout << endl;
        }
        else//继续递归剩下的图,
            DFS(head, vis, cpyQu);
        vis[v] = 0;//恢复现场
        head[v] = t;
    }
}

int main()
{
    freopen("in.txt", "r", stdin);
    //freopen("out.txt", "w", stdout);
    while(~scanf("%d%d", &h, &w) && (h || w))
    {
        memset(Gra, 0, sizeof(Gra));
        for(int i = 1; i <= h; i++)
            scanf("%s",Gra[i] + 1);
        N = getN();//获得N
        initPht();//初始化图片对角的位置
        getXY();//获得图片对角的位置
        e = 0;
        memset(flag, 0, sizeof(flag));
        for(int i = 1; i <= N; i++)//建立基本图
            buidEdge(pht[i], i);
        memset(head, -1, sizeof(head));
        memset(&Edges, 0, sizeof(EdgeNode));
        memset(&pht, 0, sizeof(Photo));
        for(int i = 1; i <= e; i++)//根据基本图建立链式前向星的存图结构
        {
            Edges[i].to = map[i].v;
            Edges[i].next = head[map[i].u];
            head[map[i].u] = i;
        }
        memset(vis, 0, sizeof(vis));
        queue<int> qu;
        DFS(head, vis, qu);//head 用于删除图的边,vis删除边,qu是每次的拓扑序列
    }
    return 0;
}

提供一组测试数据:

/*
AAA*EEEE
ACCCECCE
ACA*E*CE
*C*DEEEE
*C*DD*C*
*C**BBCB
FFF*B*CB
FCFCCCCB
FFF*BBBB

*/

时间: 2024-11-06 09:52:03

Southern African 2001 框架折叠 (拓扑序列的应用)的相关文章

图结构练习——判断给定图是否存在合法拓扑序列

图结构练习——判断给定图是否存在合法拓扑序列 Time Limit: 1000MS Memory limit: 65536K 题目描述 给定一个有向图,判断该有向图是否存在一个合法的拓扑序列. 输入 输入包含多组,每组格式如下. 第一行包含两个整数n,m,分别代表该有向图的顶点数和边数.(n<=10) 后面m行每行两个整数a b,表示从a到b有一条有向边. 输出 若给定有向图存在合法拓扑序列,则输出YES:否则输出NO. 示例输入 1 0 2 2 1 2 2 1 示例输出 YES NO #inc

图结构练习——判断给定图是否存在合法拓扑序列(sdutoj)

#include<stdio.h>#include<string.h>int d[15],map[15][15],vis[15];int main(){    int i,j,k,f,n,m,u,v;    while(~scanf("%d%d",&n,&m))    {        memset(d,0,sizeof(d));        memset(map,0,sizeof(map));        memset(vis,0,size

拓扑序列 之 hdu 5154 Harry and Magical Computer

/* AOV网(Activity On Vertex Network): 用图来表示工程:其中,用顶点表示活动:弧表示活动之间的制约关系. 工程是否顺利进行?---->AOV网是否存在有向回路 ******************************************* 用产生(包含所有) 顶点序列的方法,顶点序列满足: 在图中,若顶点vi到顶点vj存在路径, 则在序列中,顶点vi领先于顶点vj. 满足上述条件的顶点序列称为拓扑序列, 产生这一序列的过程称为拓扑排序. ********

拓扑序列变形 之 poj 1094 Sorting It All Out

/* 拓扑序列变形 之 poj 1094 Sorting It All Out 变形: 在每消去唯一一个入度为0的点后,只剩下唯一一个入度为0的点. 这样获得的n个点才是排序好的. */ 1 #include <iostream> 2 #include <cstdlib> 3 #include <cstdio> 4 #include <cstddef> 5 #include <iterator> 6 #include <algorithm&

数据结构实践项目——最短路径和拓扑序列

本文是针对[数据结构基础系列(7):图]的第2组实践例程. (程序中graph.h是图存储结构的"算法库"中的头文件,详情请单击链接-) 0710 生成树的概念 0711 最小生成树的普里姆算法 0712 最小生成树的克鲁斯卡尔算法 0713 从一个顶点到其余各顶点的最短路径 0714 每对顶点之间的最短路径 0715 拓扑排序 0716 AOE网与关键路径 纸上谈兵:"知原理"检验题目 1.针对下面的图1: (图1) (1)写出图的邻接矩阵: (2)按照Prim算

(hdu step 5.2.5)确定比赛名次(求拓扑序列)

题目: 确定比赛名次 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 337 Accepted Submission(s): 180   Problem Description 有N个比赛队(1<=N<=500),编号依次为1,2,3,....,N进行比赛,比赛结束后,裁判委员会要将所有参赛队伍从前往后依次排名,但现在裁判委员会不能直接获得

图结构练习——推断给定图是否存在合法拓扑序列(拓扑排序推断环)

图结构练习--推断给定图是否存在合法拓扑序列 Time Limit: 1000MS Memory limit: 65536K 题目描写叙述 给定一个有向图,推断该有向图是否存在一个合法的拓扑序列. 输入 输入包括多组.每组格式例如以下. 第一行包括两个整数n,m.分别代表该有向图的顶点数和边数.(n<=10) 后面m行每行两个整数a b.表示从a到b有一条有向边. 输出 若给定有向图存在合法拓扑序列,则输出YES.否则输出NO. 演示样例输入 1 0 2 2 1 2 2 1 演示样例输出 YES

拓扑序列以及排序

一句话题意:求AOV网的拓扑序列,输出按字典序最小的一个. 拓扑排序 : 由AOV网构造拓扑序列的拓扑排序算法主要是循环执行以下两步,直到不存在入度为0的顶点为止. (1) 选择一个入度为0的顶点并输出之: (2) 从网中删除此顶点及所有出边. 循环结束后,若输出的顶点数小于网中的顶点数,则输出“有回路”信息,否则输出的顶点序列就是一种拓扑序列. (摘自 : 百度百科) 方案一,用邻接矩阵来储存图,时间复杂度为 O(n * n),因为代码简单就不贴出来了. 方案二,用优先队列以及前向星来储存时间

求有向无环图的所有拓扑序列

腰酸背痛一个上午,终于搞定了.. 一 用到二个工具: 1.回溯法的算法思想 2.顺序表(主要用到了删除操作) 二 程序设计步骤: 1.读入图: 这里我没有用严格的图结构.而是用邻接矩阵来表示图,邻接矩阵放在一个txt文件中.(见后文) 读入图就是指读入这个文件. 2.计算图中顶点的入度: 用一个结构体数组来存放顶点名称和顶点的入度(我这里的结构体名称是ElemType) 3.初始化顺序表 这一步只需初始化第0号顺序表... 用2中的顶点入度数组来初试化. 4.开始计算拓扑序列 这里我们把图的每个