// HDU Online Judge// Problem 1689 Alien’s Necklace// Algorithm: Enumerate + BFS// ---- 对每一个顶点,计算经过该顶点的最短环路长,计算方法为 BFS:// ---- 在BFS中,如果遇到访问过的点,如果访问过的点是BFS隐式树中当前点的祖先,// ---- 那么该回路不经过我们枚举的点,我们按照“假设当前回路经过枚举点”计算// ---- 回路长度,由于该长度总是不小于最终最短环路长,所以对最优解不影响。// ---- 当枚举完所有顶点,也就得到了最短环路长度。// Complexity: O(VE), V为顶点数,E为边数// Author: obtuseSword// Date: 2008-05-11// Compiler: Visual Studio 2005#include <cstdio>#include <vector>#include <queue>using namespace std;vector<int> adj[1001]; // 邻接表// 读入邻接关系,创建关系图(邻接表)void create_graph(int n,int m);// 计算满足条件的最短环路的长度int min_circle(int n);//--------------------- 主函数 ---------------------////--------------------- 开始 ---------------------//int main()...{ int T; // 测试数据组数 scanf("%d",&T); for(int t=1; t<=T; t++)...{ // 读入数据 int n, m; // 顶点数,边数 scanf("%d%d",&n,&m); create_graph(n,m); // 求解 int len = min_circle(n); // 输出结果 printf("Case %d: ",t); if( len == -1 ) printf("Poor JYY. "); else printf("JYY has to use %d balls. ",len); } return 0;}//--------------------- 主函数 ---------------------////--------------------- 结束 ---------------------//// 函数:读入邻接关系,创建邻接表void create_graph(int n,int m)...{ // 清空邻接表 for(int i=1; i<=n; i++) adj[i].clear(); // 读入邻接关系 for(int j=0; j<m; j++)...{ int a,b; scanf("%d%d",&a,&b); adj[a].push_back(b); adj[b].push_back(a); }}// 函数:计算经过奇数个顶点的最短环路长int min_circle(int n)...{ int min_len = n+1; // 最短环路长 // 枚举环路搜索的起始点 for(int i=1; i<=n; i++)...{ vector<bool> visited(n+1,false); // 已访问标志 vector<int> depth(n+1); // 已访问的顶点的深度 int present_len = 0; // 已搜索的深度 // 添加搜索起始点 queue<int> que; que.push(i); visited[i] = true; depth[i] = 0; // 宽度优先搜索(BFS),以已求得的最短环路长为阈值 while( !que.empty() && ++present_len < min_len )...{ vector<int> extended; // 用于临时保存当前扩展出的顶点 // 不断扩展新的层 while( !que.empty() )...{ int v = que.front(); // 被扩展的顶点 que.pop(); // 扩展出更深一层 for(vector<int>::iterator iter = adj[v].begin(); iter != adj[v].end(); iter++)...{ // 如果发现回路 if( visited[*iter] )...{ // 假定经过顶点 i 所构成的环路的长度 int cir_len = present_len + depth[*iter]; // 回路要满足“经过奇数个顶点” if( cir_len % 2 && cir_len < min_len ) min_len = cir_len; // 如果未发现回路 }else...{ // 新顶点先暂存在 extended 中 extended.push_back(*iter); // 记录相关信息 visited[*iter] = true; depth[*iter] = present_len; } } } // 将当前扩展出的顶点加入 FIFO 队列中 for(vector<int>::iterator iter = extended.begin(); iter != extended.end(); iter++) que.push(*iter); } } // 返回结果,以 -1 表示不存在满足条件的回路 return min_len == n+1 ? -1 : min_len;}