开心小屋(smile)【DFS】【环】

本文探讨了一种特殊的图论问题——如何在一个带权无向图中找到能够无限增加心情值的最小环。通过深度优先搜索(DFS)算法,文章详细介绍了如何遍历图的节点,检测正权环,并确定最小环的节点数量。适用于30%的数据规模小于等于10,60%的数据规模小于等于100,100%的数据规模小于等于300的情况。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

>Description
Kc来到开心小屋。开心小屋是用来提升心情的。在这个小屋中有n个房间,一些房间之间有门连通。从房间i到达房间j,心情值可以加上-10000<=Cij<=10000,当然Cij可能是负的。现在kc失恋了,所以他想要知道他是否可以在这个小屋中无限地增加他的心情值,也就是无限地绕着一个环走?

请帮kc求出最小的环需要经过的房间数,来使他的心情无限增加。


>Input
第一行给出,1<=n<=300,1<=m<=5000。分别表示房间数及门的数量。
接下来m行,每行四个数:i,j,Cij,Cji

>Output
输出文件包括一行,及最小的环需要经过的房间数。
保证不会出现自环及重边。

对30%的数据,n<=10;
对60%的数据,,n<=100;
对100%的数据,n<=300;


>解题思路
竟然真的直接爆搜就过了TT

把每个点都当做start跑一遍dfs,如果再跑回start并且是个正环就累计答案,
因为跑dfs都会做标记防止在跑回去,但是我们判断环的话为了跑回原来的start,就不标记start这个点

还有一些剪枝:
当前代价为负数就return,因为我们要求的是一个正环,所以对于环中的每一个点都可以作为start,那么一定有一个点作为start的sum不会为负数(“用心理解”)
如果当前的路径数大于ans的话就return


>代码

#include <iostream>
#include <cstdio>
#include <cstring>
#define N 305
using namespace std;

struct line
{
	int to, next, c;
} a[10005];
int n, m, t, h[N], ans, start;
bool s[N], y[N];

void add (int x, int y, int l)
{
	a[++t] = (line) {y, h[x], l}; h[x] = t;
}
void dfs (int now, int c, int cnt)
{
	if (c < 0 || cnt > ans) return;
	if (now == start && cnt > 0)
	{
		if (c > 0) ans = min (ans, cnt);
		return;
	}
	for (int i = h[now]; i; i = a[i].next)
	  if (!y[a[i].to])
	  {
	  	y[a[i].to] = 1; //标记
		dfs (a[i].to, c + a[i].c, cnt + 1);
		y[a[i].to] = 0;
	  }
}

int main()
{
	ans = 300;
	scanf ("%d%d", &n, &m);
	int u, v, l;
	for (int i = 1; i <= m; i++)
	{
		scanf ("%d%d", &u, &v);
		scanf ("%d", &l);
		add (u, v, l);
		scanf ("%d", &l);
		add (v, u, l);
	}
	for (int i = 1; i <= n; i++)
	{
	  	start = i;
	  	dfs (i, 0, 0);
	}
	printf ("%d", ans);
	return 0;
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值