拓扑排序,关系运算图思维过程及题解

目录

思路:

思维过程:

一、图论第一步——存图

二、输入问题——不存负边权

题解:


思路:

这道题让我们求最小的"k"的值,其实就是让我们求权值最大的点的权值。而求一个图中点的权值,不难让我们联想到拓扑排序算法。至此,思路已经清晰。

思维过程:

一、图论第一步——存图

有图论必存图,首要的便是存图。这道题数据不大,怎么存都可以。我这里推荐用链式前向星的方法存储,这样节省空间。代码如下:

const int N = 1e3 + 2;
const int M = 1e4 + 2;
int edge[M]; //第i条边的"终点"是edge[i]
int head[N]; //第i个点引出的最后一条边的编号是head[i]
int last[M]; //第i条边的"起点"引出的上一条边的编号是last[i]
int tot = 0; //总边数

void add(int x, int y) //建边<x, y>
{
	edge[++tot] = y;
	last[tot] = head[x];
	head[x] = tot;
}

二、输入问题——不存负边权

我认为这个问题是很重要的,因为我因为这个问题挂了(60分惨剧)。注意,给边权赋值时要特判,不能有负边权,不然会挂掉,还找不出原因。

剩下的大家都很熟悉了,就在代码里看吧!

题解:

#include <bits/stdc++.h>
using namespace std;
const int N = 1e3 + 2;
const int M = 1e4 + 2;

int edge[M];
int head[N];
int last[M];
int ins[N]; //存入度
int valn[N]; //存点权
int vale[M]; //存边权

int n, m, tot = 0;

void add(int x, int y) //建边
{
	edge[++tot] = y;
	last[tot] = head[x];
	head[x] = tot;
}

bool topsort() //拓扑排序
{
	int x = 0;
	queue<int> q;
	for(int i = 1; i <= n; i++)
	{
		if(!ins[i]) //ins[i] == 0, 入度为0
			q.push(i);
	}
	while(!q.empty()) //不空
	{
		int u = q.front();
		q.pop();
		x++;
		for(int i = head[u]; i; i = last[i])
		{
			int v = edge[i];
			valn[v] = max(valn[v], valn[u] + vale[i]); //更新点权
			if(vale[i] == 0) //同步点权
				valn[u] = valn[v];
			ins[v]--; //减入度
			if(!ins[v])
				q.push(v);
		}
	}
	return x == n;
}

int main()
{
	scanf("%d %d", &n, &m);
	for(int i = 1; i <= m; i++)
	{
		int x, y, z;
		scanf("%d %d %d", &x, &y, &z);
		if(z > 0) //特判边权
		{
			ins[x]++;
			add(y, x);
			vale[tot] = z;
		}
		else
		{
			add(x, y);
			ins[y]++;
			vale[tot] = -z; //注意,小细节
		}
	}
	if(topsort()) //求最大的点权
	{
		int maxn = -0xfffffff;
		for(int i = 1; i <= n; i++)
			maxn = max(maxn, valn[i]);
		printf("%d", maxn);
	}
	else
		printf("NO");
	return 0;
} 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值