//
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;
}
// 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;
}