思路:
把字符看做点,把正方形看做边,建立有向图,拓扑排序,寻找有向环,若有环则可以无限延伸,否则不可以。
具体来说,每个点包含2个字符,一个是(A-Z),另一个是(+,-),(有一个特殊情况是00,我们不考虑,因为它不和任何一个点相连)。A+,A-,B+,B-…一共52个,分别分配下标
// 后面带+号的下标为偶数,-号的为奇数
int ID( char x1, char x2 ) {
return (x1-'A')*2 + (x2=='+' ? 0 : 1 );
}
依次读入边。组成边的两个点不是某一个正方形内的两个点,而是两个正方形各出一个点。比如A+在正方形S,其他3个点依次是B+,C+,00,那么A+要连的点不是B+,C+而是B+,C+可以向外延伸的点(另外一个正方形M的B-,C-点)。
那么如何快速得知B+,C+的可连的点(B-,C-)对应的下标呢? 亦或^。
数学知识: 偶数的亦或为自身+1,奇数的亦或为自身-1.
而0,1 对应A+,A-; 2,3对应B+,B-……
通过亦或可以快速确定其对应字母的下标。
void connect( char x1, char x2, char y1, char y2 ) {
if( x1=='0'||y1=='0' ) return;
int u = ID( x1,x2 );
int v = ID( y1,y2 ) ^ 1;
G[u][v] = 1;
}
剩下的就是dfs拓扑排序寻找有向环了。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <queue>
#include <algorithm>
using namespace std;
const int N = 52;
int G[N][N], vis[N];
int n;
// 带+号的id为偶数,-号的为奇数
int ID( char x1, char x2 ) {
return (x1-'A')*2 + (x2=='+' ? 0 : 1 );
}
void connect( char x1, char x2, char y1, char y2 ) {
if( x1=='0'||y1=='0' ) return;
int u = ID( x1,x2 );
int v = ID( y1,y2 ) ^ 1;
G[u][v] = 1;
}
//拓扑排序的dfs
bool dfs( int u ) {
vis[u] = -1;
for( int v=0; v<52; ++v ) {
if( G[u][v] ) {
if( vis[v]<0 ) return true;
else if( 0==vis[v]&&dfs(v) ) return true;
}
}
vis[u] = 1;
return false;
}
//寻找有向图是否有环
bool Find_circle() {
memset( vis,0,sizeof(vis) );
for( int u = 0; u<52; ++u ) {
if( !vis[u] ) {
if( dfs(u) ) return true;
}
}
return false;
}
int main()
{
while( cin>>n&&n ) {
memset( G,0,sizeof(G) );
char s[9];
while( n-- ) {
cin>>s;
for( int i=0; i<4; ++i ) {
for( int j=0; j<4; ++j ) {
if( i!=j ) connect( s[i*2],s[i*2+1],s[j*2],s[j*2+1] );
}
}
}
if( Find_circle() ) cout<<"unbounded\n";
else cout<<"bounded\n";
}
return 0;
}