题意:给定屏幕当前的状态,判断屏幕是否显示正常。其实就是把“覆盖”当做一条有向边,建图之后判断该图是否存在环。
思路:先建图,然后进行拓扑排序。这题建图是关键,每一个窗口有一个自己的区域,若区域a上是窗口b,则说明窗口a被窗口b覆盖,则存在一条有向边b->a,扫描9个区域之后则将所有的边添加完毕,不过会存在重复的边,将其去掉后即可。
代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <stack>
#include <string>
#include <vector>
using namespace std;
const int maxn = 10;
int screen[4][4];
vector<int> list[maxn]; //邻接表
int ind[maxn]; //入度
bool Input(){
string s;
cin>>s;
if(s == "ENDOFINPUT") return false;
for(int i = 0; i < 4; i++){
for(int j = 0; j < 4; j++)
cin>>screen[i][j];
}
cin>>s;
return true;
}
void Build(){
for(int i = 1; i <= 9; i++) {list[i].clear(); ind[i] = 0;}
for(int k = 1; k <= 9; k++){//第k个窗口
int i = (k-1)/3;
int j = (k-1)%3;
if(screen[i][j] != k) list[screen[i][j]].push_back(k);
if(screen[i][j+1] != k) list[screen[i][j+1]].push_back(k);
if(screen[i+1][j] != k) list[screen[i+1][j]].push_back(k);
if(screen[i+1][j+1] != k) list[screen[i+1][j+1]].push_back(k);
}
for(int i = 1; i <= 9; i++){//去除重复的边
list[i].erase(unique(list[i].begin(),list[i].end()),list[i].end());
}
for(int i = 1; i <= 9; i++){//统计入度
for(int j = 0; j < list[i].size(); j++){
ind[list[i][j]]++;
}
}
}
bool TopSort(){
stack<int> st;
for(int i = 1; i <= 9; i++){
if(ind[i] == 0) st.push(i);
}
for(int i = 0; i < 9; i++){
if(st.empty()) return false;
int u = st.top(); st.pop();
for(int j = 0; j < list[u].size(); j++){
int v = list[u][j];
if(--ind[v] == 0) st.push(v);
}
}//end of for
return true;
}
void Solve(){
Build();
printf("THESE WINDOWS ARE %s\n",TopSort()?"CLEAN":"BROKEN");
}
int main(){
while(Input()){
Solve();
}
return 0;
}