HDU2012 0 0表示输入结束

#include
#include
#include
using namespace std;
bool f(int s)
{

for(int i=2;i*i<=s;i++)
{
	if(s%i==0)
	return false;
		
}
return true;

}
int main()
{
int m,n,s;
while(cin>>m>>n)
{
int count=0;
if(mn&&m0)
break;
for(int i=m;i<n+1;i++)
{
s=pow(i,2)+i+41;
if(f(s))
count++;
}
if(count==(n-m+1))
cout<<“OK”<<endl;
else
cout<<“Sorry”<<endl;

}

}

<think>我们正在解决HDU1269迷宫城堡问题。题目要求判断有向图中任意两个房间是否相互连通,即整个图是否是一个强连通图。 强连通图定义:有向图G中,如果任意两个不同的顶点相互可达(即存在从u到v和从v到u的路径),则称G为强连通图。 因此,我们需要判断整个图是否只有一个强连通分量,且该强连通分量包含所有节点。 常用算法:Tarjan算法、Kosaraju算法等。这里我们使用Tarjan算法,因为它可以在一次DFS中完成强连通分量的识别。 Tarjan算法核心思想: 1. 使用深度优先搜索遍历整个图。 2. 为每个节点维护两个值:dfn[u]表示节点u在DFS遍历中的次序(时间戳),low[u]表示u或u的子树能够追溯到的最早的栈中节点的次序号。 3. 使用一个栈来存储当前访问路径上的节点。 4. 当dfn[u] == low[u]时,从栈中弹出节点直到u,这些节点组成一个强连通分量。 步骤: 1. 初始化:对每个节点,dfn数组初始化为0表示未访问),low数组初始化为0,设置一个全局时间戳index=0。 2. 遍历每个节点,如果dfn[u]为0,则进行DFS。 3. DFS过程中: - 设置dfn[u]=low[u]=++index,将u入栈,标记u在栈中。 - 对于u的每个邻接点v: - 如果v未被访问(dfn[v]==0),则递归访问v,然后更新low[u]=min(low[u], low[v]) - 如果v在栈中(说明v是u的祖先节点,且形成了环),则更新low[u]=min(low[u], dfn[v])(注意这里也可以用low[u]=min(low[u], dfn[v]),因为v在栈中,说明属于同一个强连通分量) - 如果u的dfn和low相等,说明u是一个强连通分量的根节点,开始弹栈直到u,弹出的节点构成一个强连通分量。 注意:题目要求判断整个图是否是一个强连通图,即整个图只有一个强连通分量,且该分量包含所有节点。 因此,我们可以在Tarjan算法过程中计数强连通分量的个数。如果整个图只有一个强连通分量,且该分量的大小等于节点总数,则输出"Yes",否则输出"No"。 代码实现步骤: 1. 读入数据,构建有向图(邻接表)。 2. 初始化dfn数组、low数组、栈、栈内标记数组(inStack)等。 3. 遍历每个节点,若未访问则进行Tarjan算法。 4. 统计强连通分量的个数和大小(本题只需判断是否只有一个强连通分量且包含所有节点,因此我们可以在Tarjan过程中记录每个强连通分量的大小,最后检查是否有一个分量的大小等于总节点数,并且分量个数为1?实际上,如果整个图是强连通的,那么只会有一个强连通分量,且大小为n。但注意:有可能有多个分量,所以我们需要看分量的个数是否为1,并且这个分量的大小为n。然而,在Tarjan算法中,我们统计分量个数,如果整个图是强连通的,那么我们在遍历完所有节点后,只会得到一个强连通分量,且这个分量的大小就是n。但是,我们也可以不记录每个分量的大小,而是判断分量的个数是否为1。因为如果只有一个分量,那么它必然包含所有节点(因为所有节点都被访问了)。所以,我们只需在算法结束后判断强连通分量的个数是否为1。 但是注意:如果图不连通(有多个连通分量,但这里是有向图,所以可能是多个强连通分量),那么分量个数大于1。 因此,我们只需在Tarjan过程中统计强连通分量的个数(每次弹栈时计数),最后判断个数是否为1。 注意:题目输入可能有多个测试数据,以0 0结束。 代码实现(C++): 由于题目中节点数N<=10000,边数M<=100000,所以使用邻接表存储图,Tarjan算法的时间复杂度为O(N+M),可以接受。 伪代码: while (输入n, m, 且n和m不为0) { 初始化图(邻接表) 读入m条边 初始化dfn数组(大小为n+1,初始0),low数组(大小为n+1),栈stack,inStack数组(大小为n+1,初始false),index=0, scc_count=0(强连通分量计数) 遍历每个节点i(从1到n),如果dfn[i]==0,则调用tarjan(i) 如果scc_count==1,输出"Yes",否则输出"No" } 在tarjan函数中: dfn[u] = low[u] = ++index; stack.push(u); inStack[u] = true; 遍历u的每个邻接点v: 如果dfn[v]==0(未访问): tarjan(v); low[u] = min(low[u], low[v]); 否则如果inStack[v](已访问且在栈中): low[u] = min(low[u], dfn[v]); // 注意这里也可以用low[u] = min(low[u], dfn[v]),因为dfn[v]一定小于low[u]?这里用dfn[v]更安全,因为low[v]可能还没有更新到最小(但v在栈中,说明v还在当前DFS树中,且dfn[v]已经确定,而low[v]可能还没有更新到最小,所以用dfn[v]?实际上,根据算法,应该用dfn[v]) // 回溯时判断 if (dfn[u] == low[u]) { scc_count++; // 增加一个强连通分量 int v; do { v = stack.top(); stack.pop(); inStack[v] = false; } while (v != u); } 注意:上述弹栈过程会弹出整个强连通分量,但这里我们并不需要记录每个分量的大小,只需要计数。 但是,有一个问题:如果整个图是强连通的,那么我们在DFS完第一个节点后,就会在回溯到根节点时弹出一个包含所有节点的分量吗?不一定,因为DFS可能从任意节点开始,而强连通图从任意节点开始DFS,最终都会将整个图遍历,并且在回溯到根节点时弹出整个分量?是的,因为整个图强连通,所以DFS会访问所有节点,并且最终回溯到根节点时,栈中剩下的节点都会被弹出形成一个分量。但是,如果图不是强连通的,那么可能会有多个根节点(即多个dfn[u]==low[u]的节点),从而形成多个分量。 然而,我们是在主函数中循环调用tarjan的(因为图可能不连通,这里的有向图不连通是指有多个强连通分量,且它们之间没有连接),所以即使图有多个强连通分量,我们也会通过循环调用tarjan来访问所有节点(因为每个节点都会被遍历到)。 但是注意:在同一个强连通分量中的节点,通过一次DFS(从该分量中任意节点开始)就能访问整个分量,并且弹出整个分量。而其他分量的节点,则会在循环中再次调用tarjan(因为dfn为0)进行处理。 因此,我们只需要在tarjan函数中,每当弹出一个分量时,计数scc_count++。最后判断scc_count是否等于1。 但是,注意:题目要求的是整个图是强连通的,即只能有一个强连通分量。 因此,代码实现如下(C++):</think>### HDU1269 迷宫城堡 解题思路及代码实现 #### 问题分析 题目要求判断有向图中任意两个房间是否**相互连通**,即整个图是否是一个**强连通图**。强连通图定义为:图中任意两个顶点 $u$ 和 $v$ 都存在从 $u$ 到 $v$ 和从 $v$ 到 $u$ 的路径[^2]。 #### 算法选择:Tarjan 算法 使用 **Tarjan 算法**求解强连通分量(SCC),其核心思想是通过一次 DFS 遍历完成 SCC 识别: 1. **时间戳 $dfn[u]$**:记录节点 $u$ 的 DFS 访问顺序。 2. **追溯值 $low[u]$**:记录 $u$ 或其子树能追溯到的最早栈中节点的时间戳。 3. **栈维护**:存储当前 DFS 路径上的节点。 4. **SCC 判定**:当 $dfn[u] = low[u]$ 时,从栈顶弹出节点直到 $u$,这些节点构成一个 SCC[^2]。 **算法步骤**: 1. 初始化 $dfn$ 和 $low$ 数组,全局时间戳 $index = 0$。 2. 遍历所有未访问节点,进行 DFS: - 设置 $dfn[u] = low[u] = ++index$,将 $u$ 入栈。 - 遍历邻居 $v$: - 若 $v$ 未访问,递归访问 $v$,更新 $low[u] = \min(low[u], low[v])$。 - 若 $v$ 在栈中,更新 $low[u] = \min(low[u], dfn[v])$。 - 若 $dfn[u] = low[u]$,弹出栈中节点直到 $u$,记为一个 SCC。 3. **判定条件**:整个图是强连通图当且仅当 SCC 数量为 1。 #### 复杂度分析 - **时间复杂度**:$O(N + M)$($N$ 为节点数,$M$ 为边数)。 - **空间复杂度**:$O(N + M)$(邻接表存储图)。 #### 代码实现(C++) ```cpp #include <iostream> #include <vector> #include <stack> #include <cstring> #include <algorithm> using namespace std; const int MAXN = 10005; vector<int> graph[MAXN]; int dfn[MAXN], low[MAXN]; bool inStack[MAXN]; stack<int> stk; int index, scc_count; void tarjan(int u) { dfn[u] = low[u] = ++index; stk.push(u); inStack[u] = true; for (int v : graph[u]) { if (!dfn[v]) { tarjan(v); low[u] = min(low[u], low[v]); } else if (inStack[v]) { low[u] = min(low[u], dfn[v]); } } if (dfn[u] == low[u]) { scc_count++; while (true) { int v = stk.top(); stk.pop(); inStack[v] = false; if (v == u) break; } } } int main() { int n, m; while (cin >> n >> m) { if (n == 0 && m == 0) break; // 初始化 for (int i = 1; i <= n; i++) graph[i].clear(); memset(dfn, 0, sizeof(dfn)); memset(low, 0, sizeof(low)); memset(inStack, false, sizeof(inStack)); while (!stk.empty()) stk.pop(); index = scc_count = 0; // 建图 for (int i = 0; i < m; i++) { int a, b; cin >> a >> b; graph[a].push_back(b); } // 遍历所有未访问节点 for (int i = 1; i <= n; i++) { if (!dfn[i]) tarjan(i); } // 输出结果 cout << (scc_count == 1 ? "Yes" : "No") << endl; } return 0; } ``` #### 输入输出示例 **输入**: ``` 3 3 1 2 2 3 3 1 3 3 1 2 2 3 3 2 0 0 ``` **输出**: ``` Yes No ``` #### 关键点说明 - **栈的作用**:存储当前 DFS 路径,确保只考虑同一路径上的节点。 - **$low[u]$ 更新**:通过邻居 $v$ 的状态更新 $u$ 的追溯值,识别环路。 - **SCC 计数**:每完成一次弹栈操作,SCC 数量增加 1。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值