#include<iostream>
#include<cstdio>
#include<string.h>
#include<string>
#include<cstring>
using namespace std;
const char s[6]="START";
const char e[4]="END";
const char ee[11]="ENDOFINPUT";
char order[15];
int m[5][5];
int g[10][10];
bool visit[10];
int rec[10];
const int possible[4][4][4]={{{1},{1,2},{2,3},{3}},{{1,4},{1,2,4,5},{2,3,5,6},{3.6}},{{4,7},{4,5,7,8},{5,6,8,9},{6,9}},{{7},{7,8},{8,9},{9}}};
int main(){
int i,j,k;
while(scanf("%s",order)!=EOF){
if(strcmp(ee,order)==0)
break;
memset(m,0,sizeof(m));
memset(g,0,sizeof(g));
memset(rec,0,sizeof(rec));
memset(visit,0,sizeof(visit));
for(i = 0; i < 4; ++i){
for(j = 0; j < 4; ++j){
scanf("%d",m[i]+j);
}
}
int tmp,cur;
for(i = 0; i < 4; ++i){
for(j = 0; j < 4; ++j){
//m[i][j]依次为1,2,...,9的起点
cur = m[i][j];
for(k = 0; k < 4; ++k){
tmp = possible[i][j][k];
if(tmp && tmp != cur){
if(g[tmp][cur] == 0)
++rec[cur];
g[tmp][cur] = 1;
}
}
}
}
scanf("%s",order);
int total = 9;
bool isok = true;
while(total){
for(i = 1; i < 10; ++i){
if((!visit[i])&&(rec[i]==0)){
break;
}
}
if(i == 10){
isok = false;
break;
}
visit[i] = 1;
--total;
for(j = 0; j < 10; ++j){
if(g[i][j]){
--rec[j];
}
}
}
if(isok){
printf("THESE WINDOWS ARE CLEAN\n");
}
else{
printf("THESE WINDOWS ARE BROKEN\n");
}
}
return 0;
}
思路:将4x4的格子中每个位置可能出现的数字列出来,存在possible数组中,然后对每个位置,取现在屏幕上的数字,说明这个数字把在这个位置其它可能出现的数字覆盖了(也就是这块2x2的格子把其余可能覆盖这个位置的2x2的格子给覆盖了),那么就在两者之间建一条有向边(注意不要建立重复边),然后增加边终点的入度,如果可以拓扑排序,说明屏幕是clean,否则是broken~
难点:1.建立图论模型 2.不要建立重复边 3.想到遍历每个位置可能出现的数字