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:
![]()
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:
![]()
If window 4 were then brought to the foreground:
![]()
… 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:
ENDOFINPUTNote 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 CLEANOtherwise, 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排序条件。
![]()
将样例的第二组输入构造成有向图如下图所示,其中1->4和4->1均有边,故不能构成topo排序。
将图构造好后,即刻使用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;
}
此题为拓扑算法的经典题型。