poj 2585,zoj 2193 Window Pains【拓扑排序思想判断图是否存在环】
解题报告参见《图论算法理论、实现及应用》 王桂平主编 北京大学出版社 P74。
View Code
#include<stdio.h> #include<iostream> #include<string.h> #include<string> using namespace std; const string end = "ENDOFINPUT"; string cover[4][4]; //表示能覆盖(i,j)位置的窗口的集合。 int mp[5][5]; //屏幕快照上最后显示的内容。 bool g[10][10]; //邻接表。 bool exist[10]; //某个窗口是否在屏幕快照上出现。 int tot; //记录屏幕上总共出现的不同的窗口种类,以这些窗口为顶点,构建有向图。 int id[10]; //入度。 //初始化操作。 统计覆盖(i,j)位置的窗口的集合。 void calc() { for(int k = 1; k <= 9; k++) { int i = (k-1)/3; int j = (k-1)%3; cover[i][j] += (k + '0'); //第k个窗口左上角位置。 cover[i+1][j] += (k + '0'); //第k个窗口右上角位置。 cover[i][j+1] += (k + '0'); //第k个窗口左下角位置。 cover[i+1][j+1] += (k + '0'); //第k个窗口右下角位置。 } } void build() //构建有向图。 { memset(g, 0, sizeof(g)); memset(id, 0, sizeof(id)); for(int i = 0; i < 4; i++) { for(int j = 0; j < 4; j++) { int len = cover[i][j].length(); for(int p = 0; p < len; p++) { if( !g[mp[i][j]][cover[i][j][p] - '0'] && mp[i][j] != cover[i][j][p] - '0') { g[mp[i][j]][cover[i][j][p] - '0'] = 1; id[cover[i][j][p] - '0']++; } } } } } bool check() //判断有向图是否存在有向环。拓扑排序思想。 { for(int k = 0; k < tot; k++) { int i = 1; //统计出现在屏幕快照中、并且入度不为0的窗口个数。 while( !exist[i] || (i <= 9 && id[i] > 0) ) { i++; } //i>9说明所有窗口入度均不为0,则必存在环。 if(i > 9) { return 0; } //处理编号为i的窗口,删除该窗口以及其相应出边。 exist[i] = 0; for(int j = 1; j <= 9; j++) { //删除相应顶点入边(入度减1)。 if(exist[j] && g[i][j]) { id[j]--; } } } return 1; } int main() { calc(); string str; while(cin >> str) { if(str == end) { break; } memset(exist, 0, sizeof(exist)); tot = 0; //tot为屏幕快照中出现的窗口种类的个数。 for(int i = 0; i < 4; i++) { for(int j = 0; j < 4; j++) { scanf("%d", &mp[i][j]); if( !exist[mp[i][j]] ) { tot++; } exist[mp[i][j]] = true; } } cin >> str; build(); if( check() ) { printf("THESE WINDOWS ARE CLEAN\n"); } else { printf("THESE WINDOWS ARE BROKEN\n"); } } return 0; }