hdu-1269

                                                 迷宫城堡

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 10419    Accepted Submission(s): 4682


Problem Description
为了训练小希的方向感,Gardon建立了一座大城堡,里面有N个房间(N<=10000)和M条通道(M<=100000),每个通道都是单向的,就是说若称某通道连通了A房间和B房间,只说明可以通过这个通道由A房间到达B房间,但并不说明通过它可以由B房间到达A房间。Gardon需要请你写个程序确认一下是否任意两个房间都是相互连通的,即:对于任意的i和j,至少存在一条路径可以从房间i到房间j,也存在一条路径可以从房间j到房间i。
 

Input
输入包含多组数据,输入的第一行有两个数:N和M,接下来的M行每行有两个数a和b,表示了一条通道可以从A房间来到B房间。文件最后以两个0结束。
 

Output
对于输入的每组数据,如果任意两个房间都是相互连接的,输出"Yes",否则输出"No"。
 

Sample Input
  
  
3 3 1 2 2 3 3 1 3 3 1 2 2 3 3 2 0 0
 

Sample Output
  
  
Yes No
题目来源:http://acm.hdu.edu.cn/showproblem.php?pid=1269
题目考点: 这是一道考查强连通分量的基础题目
解体思路:这个问题搞了好几天,终于对tarjan算法理解了。关于这个算法主要要理解low[],与dfn[]的意思。在解释之前,先说几个性质。
1.每个强连通分量之间不可能有公共顶点
2.若叶子结点没有到其祖先的路径,那它肯定会独立成为一个强连通分量。
接下来应用一下网上我认为最好理解的算法原理解释:

tarjan算法的基本框架就是dfs,其基本原理是有向图至少存在一棵深搜子树,其结点集合构成一个强连通分量,这是显然的,因为必定有一个强连通分量最后被dfs,这个强连通分量的结点构成深搜树的一棵子树。

有了以上结论后,求强连通分量就有思路了,我们在每棵子树深搜完成后判断这棵子树是否构成强连通分量即可,关键在于如何判断一棵子树是否构成强连通分量。

注意到最先搜索完的子树是那些叶子结点,要判断叶子结点是否构成强连通分量很简单,若存在叶子结点与其祖先结点的连边,则该叶子结点不构成强连通分量,否则构成强连通分量。tarjan算法用pre[V]数组和low[V]数组来判断子树是否构成强连通分量,pre[v]保存结点v在先序遍历中的访问顺序,以下统称深度优先数,low[v]保存从v出发能到达的所有结点的最小深度优先数,用叶子结点来解释,v为叶子结点,
当low[v]<pre[v]时,表明存在v到其祖先结点的连边,v不构成强连通分量;
当low[v]==pre[v]时,表明不存在v到其祖先结点的连边,v构成强连通分量。

若深搜树中存在一个叶子结点构成强连通分量,则通过以上判断可以求出,也即求出了第一个强连通分量;
若深搜树中所有叶子结点都不构成强连通分量,此时叶子结点必定与其父结点同在一个强连通分量中,可以将其缩到父结点中(具体操作是更新父结点的low数组),原来的父结点就变成了“大”叶子结点,还是通过low[v]=?pre[v]来判断这个“大”叶子结点是否构成强连通分量,一直这样下去,叶子结点将越来越大,直到求出第一个强连通分量为止。

在求出第一个强连通分量后,我们将其包含的结点在原图中删除,问题又转化成了求第一个强连通分量的问题,理解还是一样的,以此类推,直到所有的强连通分量均被求出,此时算法结束。

代码如下:
#include<stdio.h>
#include<string.h>
#include<stack>
#include<vector>
using namespace std;
#define  MAXM 10010
vector<int>scc[MAXM];
stack<int>S;
struct stu
{
	int fo,to,ne;
};
stu edge[MAXM*10];
int n,m,num;
int head[MAXM];
int dfs_clock,scc_cnt;
int low[MAXM];
int dfn[MAXM];
int sccno[MAXM];
int instack[MAXM]; 
void inin()
{
   num=0;
   memset(head,-1,sizeof(head));	
}
void addedge(int a,int b)
{
	stu E={a,b,head[a]};
	edge[num]=E;
	head[a]=num++;
}
void tarjan(int u)
{
	int v;
	low[u]=dfn[u]=++dfs_clock;
	S.push(u);
	instack[u]=true;
	for(int i=head[u];i!=-1;i=edge[i].ne)
	{
		v=edge[i].to;
		if(!dfn[v])
		{
			tarjan(v);
			low[u]=min(low[u],low[v]);//为以后判断是否为子叶结点 
		}
		else if(instack[v])//在栈里,可以到达它的父节点 
		low[u]=min(low[u],dfn[v]); 	//将它和它的父节点合并成一个大节点	
	}
	if(low[u]==dfn[u])
	{
		scc_cnt++;
		scc[scc_cnt].clear();
	    do
	    {
	    	v=S.top();
	    	S.pop();
	    	sccno[v]=scc_cnt;//v属于第几个scc_cnt
			scc[scc_cnt].push_back(v); 
	    }while(v!=u);
	}
}
void slove(int n)
{
	memset(low,0,sizeof(low));
	memset(dfn,0,sizeof(dfn));
	memset(sccno,0,sizeof(sccno));
	memset(instack,0,sizeof(sccno));
	dfs_clock=scc_cnt=0;//初始化时间戳和SCC数目 
	for(int i=1;i<=n;i++)
	{
		if(!dfn[i])tarjan(i);//节点没有访问过 
	}
}
int main()
{
	int a,b;
	while(scanf("%d%d",&n,&m),n|m)
	{
		inin();
		while(m--)
		{
			scanf("%d%d",&a,&b);
			addedge(a,b);
		}
		slove(n);//此处从第一个节点开始 
		if(scc_cnt==1)
		printf("Yes\n");
		else
		printf("No\n");
	}
	return 0;
	
}


内容概要:本文详细介绍了使用COMSOL进行三相电力变压器温度场与流体场耦合计算的具体步骤和技术要点。首先讨论了变压器温升问题的重要性和现有仿真与实测数据之间的偏差,接着阐述了电磁--流三场耦合建模的难点及其解决方法。文中提供了关键的材料属性设置代码,如变压器油的密度和粘度随温度变化的关系表达式,并强调了网格划分、求解器配置以及后处理阶段需要注意的技术细节。此外,还分享了一些实用的经验和技巧,例如采用分离式步进求解策略、优化网格划分方式等,确保模型能够顺利收敛并获得精确的结果。最后,作者推荐了几种常用的湍流模型,并给出了具体的参数设置建议。 适用人群:从事电力系统设计、变压器制造及相关领域的工程师和技术人员,特别是那些希望深入了解COMSOL软件在复杂多物理场耦合计算方面应用的人群。 使用场景及目标:适用于需要对变压器内部温度分布和油流情况进行精确模拟的研究或工程项目。主要目的是提高仿真精度,使仿真结果更加贴近实际情况,从而指导产品设计和优化运行参数。 其他说明:文中不仅包含了详细的理论解释和技术指导,还提供了一些实际案例供读者参考。对于初学者来说,可以从简单的单相变压器开始练习,逐步掌握复杂的三相变压器建模技能。同时,作者提醒读者要注意单位的一致性和材料属性的准确性,这是避免许多常见错误的关键所在。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值