uva 1572

来源:互联网 发布:知已知彼的意思是什么 编辑:程序博客网 时间:2024/05/16 17:42

原题

锻炼思维的题, 这种类似的题都需要把问题转化为图论模型, 然后判断是否有环路(验证是否为DAG, 有向无环图)

图中共有52种不同的标记, 也就是有52个顶点, 而且因为字母相同的顶点之间有一定的关系, 所以读入边的时候需要做一点小处理, 

需要先把边的一端的字母转换符号之后再标记边

一开始有一个理解的误区, 以为这道题可以转化为无向图, 因为看上去似乎并没有方向的问题

但后来发现用无环图会在一种边界情况(如一个block有两个相同的vertex)产生误判

还有就是复习了一下拓扑排序, 目前接触到的有两种, 一个是依次找度为0的顶点输出, 比较直观的方法

第二则是DFS, 这个和第一种方法思路完全相反, 因为DFS完之后生成一棵DFS树, 

把这棵DFS树从最底层的叶节点(也就相当于度为0) 开始依次向上层输出, 也就是逆序的层序遍历

这种方法, 在DFS的时候, 先把其所有子树都DFS完毕再输出当前结点即可实现.

这道题我就用的第二种方法, 比较方便用于找环, 遍历的时候如果遇到已经标记visited的结点则说明有环

不过一开始忽略了一点, 就是遍历完子结点回溯的时候记得要再把该点的visited标记为false, 否则后面显然就会错了, 检查这个错误还检查了好久..

AC代码如下:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <string>
#include <vector>
#include <set>
#include <stack>
#include <queue>
#include <deque>
#include <map>
#include <list>
#include <cassert>
#include <iomanip>


using namespace std;
const int MAXN = 52; // 原坐标系 
typedef long long LL;
/*
uva 1572
关键 :  1.  注意到可以转化为图论模型, 每个大写字母及其符号作为一个顶点, 
每个block代表2条有向路(因为可以任意旋转和翻转) ,则问题转化为是否能够找到一条有向图的环 
2.  【关键步骤】: 根据题意要求, 读入一个block时要进行转换, 如读入K+00P-00
则代表 Edge[K-][P-] = true 而非  Edge[K+][P-] = true
3.  拓扑排序有多种实现方式, 常用的有DFS, 找入度为0的点等等 
4.  不应该转化为无向图模型, 因为在这种方法下若有 A+A+0000 类似的方块则也会判unbounded 
5.  考虑到形如 K+K+K+K+ K-K-K-K-的 边界情况 
6.  用DFS找环, 回溯的过程中记得取消访问记录 
*/


map<char,int> ID;
bool Edge[MAXN][MAXN];
bool isCircle;
bool mark[MAXN]; //DFS时标记是否走过 


char trans(char a){ // 转换大小写 
return (a^0x20);
}


void Link(char c1, char c2){
int id1 = ID[c1];
int id2 = ID[c2];
Edge[id1][id2] = true;
// cout << id1 << " " << id2 << endl;
}


void DFS(char s){
int id = ID[s];
if( !mark[id] ){
mark[id] = true;
// cout << s << " ";

else isCircle = true;
for(int i=0; i<MAXN && !isCircle; i++){
if( Edge[id][i] ){
if( i&1 ){
DFS('A'+i/2);
}else{
DFS('a'+i/2);
}
}
}
mark[id] = false;
}


int main(){
int  N;
string str, tmp;
for(int i=0, n=0; i<26; i++){// ID为偶数则小写, 否则大写 
ID['a'+i] = n++;
ID['A'+i] = n++;

while( (cin>>N) && N>0 ){
memset(Edge,0,sizeof(Edge));
char v[4]; // 记录输入的顶点 序号 
for(int i=0; i<N; i++){
int n=0;
cin >> str;
for(int j=0; j<8; j+=2 ){
tmp = str.substr(j,2);
if( tmp!="00" ){
if( tmp[1]=='-' ){// 转换为小写 
tmp[0] = trans(tmp[0]);
}
v[n++] = tmp[0];
}
}
for(int j=0; j<n; j++){
for(int k=0; k<n; k++){
if( j!=k ) Link(trans(v[j]), v[k]);
}
}
}
isCircle = false;
for(int i=0; i<26 && !isCircle; i++){
memset(mark,0,sizeof(mark));
DFS('a'+i);
memset(mark,0,sizeof(mark));
DFS('A'+i);
}
if( isCircle ) cout << "unbounded" << endl;
else cout << "bounded" << endl;
}



return 0;
}








0 0
原创粉丝点击