死嗑 拓扑排序

一、 【常用】拓扑排序模板(BFS 做法)

#include<bits/stdc++.h>
using namespace std;

const int N=105;
vector<int> G[N];
int in[N],ans[N],n,m,tmp;
int pd;	//判断有无环 

//BFS拓扑排序 
void topu()
{
	queue<int> q;
	for(int i=1;i<=n;++i)
		if(in[i]==0) q.push(i);
	int t;tmp=0;
	while(!q.empty())
	{
		t=q.front();q.pop();pd++; 
		ans[tmp++]=t;
		for(int i=0;i<G[t].size();++i)
		{
			in[G[t][i]]--;
			if(in[G[t][i]]==0) q.push(G[t][i]);
		}
	}
	if(pd<n) {	//若出队数少于入队数,说明存在入度始终不为 0的节点
		cout<<"有环"<<endl;
		return; 
	}
	for(int i=0;i<n;++i)
		cout<<ans[i]<<' ';
	cout<<endl;
}

int main()
{
	while(~scanf("%d%d",&n,&m),n>0&&m>0)
	{
		memset(in,0,sizeof(in));
		memset(ans,0,sizeof(ans));
		for(int i=1;i<=n;++i) G[i].clear();
		
		//建图 
		int a,b;
		for(int i=0;i<m;++i)
		{
			cin>>a>>b;
			G[a].push_back(b);
			in[b]++;
		}
		topu();
	}
	return 0;
}

二、 拓扑排序模板(DFS 做法)

#include<bits/stdc++.h>
using namespace std;

const int N=105;
vector<int> G[N],book(N); //book标记一定要初始化
int ans[N];
int n,m,tmp;

bool dfs(int u)
{
	book[u]=-1;
	for(int i=0;i<G[u].size();++i)
	{
		if(book[G[u][i]]==-1) {return false;} //如果该节点中有节点也在访问中 说明是有向环
		else if(book[G[u][i]]==0) {dfs(G[u][i]);} //如果该节点指向的节点没被访问过 则对其进行递归访问
	}
	book[u]=1; ans[--tmp]=u;
	return true;
}

//DFS拓扑排序 
bool topu()
{
	tmp=n;
	for(int i=1;i<=n;++i)
		if(book[i]==0) if(!dfs(i)) {return false;}
	return true;
}

int main()
{
	while(~scanf("%d%d",&n,&m),n>0&&m>0)
	{
		memset(ans,0,sizeof(ans));
		for(int i=1;i<=n;++i) G[i].clear();
		book.clear();
		
		//建图 
		int a,b;
		for(int i=0;i<m;++i)
		{
			cin>>a>>b;
			G[a].push_back(b);
		}
		if(!topu()) cout<<"有环"<<endl;
		else for(int i=0;i<n;++i)	//else还可以直接和 for连接 
			cout<<ans[i]<<' ';
		cout<<endl;
	}
	return 0;
}

关于拓扑排序的小提示

以上面的拓扑图为例,要是用 B F S BFS BFS 拓扑排序,那么结果为 123546 123546 123546,但要是用 D F S DFS DFS 拓扑排序 ,结果为 125634 125634 125634,两者结果不一样

一般情况下,我们想的和 B F S BFS BFS 拓扑排序的结果是一致的,即 4 4 4 6 6 6 都在 3 3 3 5 5 5 后面,但从 D F S DFS DFS 拓扑排序的结果来看显然不是,它的 3 3 3 6 6 6 的前面,我们可以仔细从拓扑排序的定义思考,定义只是规定了箭头所指的元素一定要在箭头后的元素的后面,而 3 3 3 6 6 6 没有直接关系,因此是惯性思维导致我们的猜想存在漏洞

补充:一般提到 D A G DAG DAG(有向无环图)就要想到拓扑排序

给任务排序 Ordering Tasks

在这里插入图片描述

#include<bits/stdc++.h>
using namespace std;

const int N=105;
vector<int> G[N];
pair<int,int> mmp[N*N];	//pair占两倍空间 
int in[N],ans[N],n,m,tmp;

//BFS拓扑排序 
void topu()
{
	queue<int> q;
	for(int i=1;i<=n;++i)
		if(in[i]==0) q.push(i);
	int t;tmp=0;
	while(!q.empty())
	{
		t=q.front();q.pop();
		ans[tmp++]=t;
		for(int i=0;i<G[t].size();++i)
		{
			in[G[t][i]]--;
			if(in[G[t][i]]==0) q.push(G[t][i]);
		}
	}
	for(int i=0;i<n;++i)
		cout<<ans[i]<<' ';
	cout<<endl;
}

int main()
{
	while(~scanf("%d%d",&n,&m),n>0) //这里有个坑,不可以加上 &&m>0
	{
		memset(in,0,sizeof(in));
		memset(ans,0,sizeof(ans));
		for(int i=1;i<=n;++i) G[i].clear();
		
		//并没有保证关系不重复
		int a,b;
		for(int i=0;i<m;i++)
		{
			cin>>a>>b;
			mmp[i]=make_pair(a,b);
		}
		sort(mmp,mmp+m);
		int len=unique(mmp,mmp+m)-mmp;
		for(int i=0;i<len;++i)
		{
			G[mmp[i].first].push_back(mmp[i].second);
			in[mmp[i].second]++;
		}
		topu();
	}
	return 0;
}

思路
其实就是模板题,只是题目并没有保证输入的数据不重复,因此要加上 p a i r pair pair 方法去重

补充:关于使用 p a i r 、 s o r t 、 u n i q u e pair、sort、unique pairsortunique 去重可以参考 C++ STL库 容器与方法 p a i r pair pair

神经网络

在这里插入图片描述
在这里插入图片描述在这里插入图片描述

#include<bits/stdc++.h>
using namespace std;

const int N=105;
vector<int> G[N];
queue<int> q;
int out[N],C[N],hd[N];
bool book[N];
int n,m,a,b,c,cnt=0,flag=0,flag_sum=0;

struct Edge {
	int to,val,nxt;
}e[N*N];

void build(int u,int v,int w)
{
	e[++cnt].to=v;
	e[cnt].val=w;
	e[cnt].nxt=hd[u];
	hd[u]=cnt;
}

void topu()
{
	while(!q.empty())
	{
		int tmp=q.front();
		q.pop();
		for(int i=hd[tmp];i;i=e[i].nxt)
		{
			C[e[i].to]+=C[tmp]*e[i].val;
			if(C[e[i].to]>0&&book[e[i].to]==0) { //只有状态大于 0的神经元才能继续传递信息 
				book[e[i].to]=1;
				q.push(e[i].to);
			}
		}
	}
}

int main()
{
	cin>>n>>m;
	for(int i=1;i<=n;++i)
	{
		cin>>a>>b;
		//这里不可以直接减,初始层也有可能有阈值,但不能减去(题目要求) 
		if(a>0)
		{
			C[i]=a;
			book[i]=1;
			q.push(i);
		}
		else C[i]=a-b;
	}
	
	for(int i=0;i<m;++i)
	{
		cin>>a>>b>>c;
		build(a,b,c);
		out[a]++;	//因为每层节点指向的一定是下一层的节点,所以不用记录入度,出度是用来判断输出层的 
	}
	
	topu();
	
	for(int i=1;i<=n;++i)
	{
		if(out[i]==0)
		{
			flag_sum++;
			if(C[i]>0) cout<<i<<' '<<C[i]<<endl; //只输出状态大于 0的输出层的神经元
			else if(C[i]==0) flag++;
		}
	}
	if(flag_sum==flag) cout<<"NULL"<<endl;	//若输出层的神经元最后状态均为 0,则输出 NULL
	
	return 0;
}

思路
题目意思就是从输入层到输出层的神经元逐个传递信息,最后输出状态不为 0 的输出层神经元

因为是 D A G DAG DAG 所以想到用拓扑排序,但并不是套用模板(因为根本用不到入度),只是运用了思想
其实题挺简单的,就是坑有点多,比如输入层的神经元不能减去阈值 (然而题目根本没说啊)

困扰我半小时的坑点:不能在每次 w h i l e while while 循环开始时才 book[tmp]=1,要在最开始记录输出层时 book[i]=1 和 每次判断结束后 book[e[i].to]=1,是因为判断条件有 book[e[i].to]==0,如果用前者方法标记,那么在遍历到下一层节点前就并不会被标记到,也就是标记没有用,从而导致 C[e[i].to]+= 重复计算

补充:关于链式前向星可以参考 这篇博客

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值