Window Pains (POJ NO.1587 拓扑排序)

POJ 1587 Window Pains

总时间限制: 1000ms
内存限制: 65536kB

Question

description
Boudreaux likes to multitask, especially when it comes to using his computer. Never satisfied with just running one application at a time, he usually runs nine applications, each in its own window. Due to limited screen real estate, he overlaps these windows and brings whatever window he currently needs to work with to the foreground. If his screen were a 4 x 4 grid of squares, each of Boudreaux’s windows would be represented by the following 2 x 2 windows:
sample
When Boudreaux brings a window to the foreground, all of its squares come to the top, overlapping any squares it shares with other windows. For example, if window 1and then window 2 were brought to the foreground, the resulting representation would be:
1
If window 4 were then brought to the foreground:
2
… and so on …

Input
Input to this problem will consist of a (non-empty) series of up to 100 data sets. Each data set will be formatted according to the following description, and there will be no blank lines separating data sets.

A single data set has 3 components:
1. Start line - A single line:
START
2. Screen Shot-Four lines that represent the current graphical representation of the windows on Boudreaux’s screen. Each position in this 4 x 4 matrix will represent the current piece of window showing in each square. To make input easier, the list of numbers on each line will be delimited by a single space.
3. End line - A single line:
END
After the last data set, there will be a single line:
ENDOFINPUT

Note that each piece of visible window will appear only in screen areas where the window could appear when brought to the front. For instance, a 1 can only appear in the top left quadrant.

Output
For each data set, there will be exactly one line of output. If there exists a sequence of bringing windows to the foreground that would result in the graphical representation of the windows on Boudreaux’s screen, the output will be a single line with the statement:
THESE WINDOWS ARE CLEAN

Otherwise, the output will be a single line with the statement:
THESE WINDOWS ARE BROKEN

样例输入

START
1 2 3 3
4 5 6 6
7 8 9 9
7 8 9 9
END
START
1 1 3 3
4 1 3 3
7 7 9 9
7 7 9 9
END
ENDOFINPUT

样例输出

THESE WINDOWS ARE CLEAN
THESE WINDOWS ARE BROKEN

My Hints

Algorithm

此题一开始想到暴力破解,但这题放在在数据结构的图的练习题中(果然还是会被影响【捂脸.jpg】),所以后来想到拓扑排序

即把九个窗口看成九个点:由题意可知屏幕的编号为(0,1)的小格中可能出现1,2两个数字,若显示为1,则说明选中1之前应先选择2,故2->1有一条有向边;若显示为2,则说明选中2之前应先选择1,故1->2有一条有向边。

将样例的第一组输入构造成有向图如下图所示,其中无环,满足topo排序条件。
topo1
将样例的第二组输入构造成有向图如下图所示,其中1->4和4->1均有边,故不能构成topo排序。
topo2

将图构造好后,即刻使用topo排序算法对窗口显示进行判定。

所谓拓扑排序,就是让图中所有有向边都由左指向右,同时将所有顶点排列在一条水平线上。本次算法根据广度优先的顺序一次访问入度为0的顶点,并将访问过的顶点添加至链表末尾。
该算法将访问过的顶点u视为已结束,同时将下一顶点v的入度减一。这一操作相当于删除边。不断删除边可以使v的入度降为0,此时我们便可以访问顶点v,然后将v加入链表中。

Codes

//转自http://blog.csdn.net/u013480600/article/details/30513421

#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#include<queue>
#define max_n 10
using namespace std;

vector<int> value[max_n][max_n];//每个小格可能出现的数字 
int dr[] = {0,1,0,1};//窗口的四个位置 
int dc[] = {0,0,1,1};
int g[max_n][max_n],in[max_n];//构造图与入度 
int sum;
string str;

void topo(){
    queue<int> que;
    for (int i = 0;i < 9;i++){
        if (in[i] == 0){
            que.push(i);
        }
    }
    sum = 0;//记录我们删除的0入度点
    while (!que.empty()){
        int u = que.front();que.pop();
        for (int i = 0;i < 9;i++){
            if (g[u][i] == 1){
                g[u][i] = 0;
                if (--in[i] == 0) que.push(i);
            }
        }
        sum++;
    }
    if (sum == 9) cout << "THESE WINDOWS ARE CLEAN" << endl;
    else cout << "THESE WINDOWS ARE BROKEN" << endl;
}

int main(int argc, char** argv) {

    //处理0-8每个应用所在的方格vector
    for (int i = 0;i < 9;i++){

        //i应用左上角的格子所在的(r,c)
        int r = i/3,c = i%3;

        //i应用所在的其他3个点
        for (int dir = 0;dir < 4;dir++){
            int nr = r + dr[dir],nc = c + dc[dir];
            value[nr][nc].push_back(i);//将i压入对应方格的vector中
        }
    }

    while (getline(cin,str)){
        if (str == "ENDOFINPUT") break;
        memset(g,0,sizeof(g));
        memset(in,0,sizeof(in));
        for (int i = 0;i < 4;i++){
            for (int j = 0;j < 4;j++){
                int v;
                cin >> v;
                v--;

                //构造有向边
                for (int k = 0;k < value[i][j].size();k++){
                    if ((value[i][j])[k] != v){
                        int x = (value[i][j])[k];
                        if (g[x][v] == 0){//这个判断可以跳过重复的有向边 
                            g[x][v] = 1;
                            in[v]++;
                        }
                    }
                }
            }
        }
        cin.get();getline(cin,str);
        topo();
    }
    return 0;
}

此题为拓扑算法的经典题型。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值