开心小屋(smile) \operatorname{开心小屋(smile)} 开心小屋(smile)
题目链接: SSL比赛 1498 \operatorname{SSL比赛\ 1498} SSL比赛 1498
题目
Kc 来到开心小屋。开心小屋是用来提升心情的。在这个小屋中有 n n n 个房间,一些房间之间有门连通。从房间 i i i 到达房间 j j j ,心情值可以加上 − 10000 < = C i j < = 10000 -10000<=C_{ij}<=10000 −10000<=Cij<=10000 ,当然 C i j C_{ij} Cij 可能是负的。现在 kc 失恋了,所以他想要知道他是否可以在这个小屋中无限地增加他的心情值,也就是无限地绕着一个环走?
请帮 kc 求出最小的环需要经过的房间数,来使他的心情无限增加。
输入
第一行给出, 1 < = n < = 300 1<=n<=300 1<=n<=300 , 1 < = m < = 5000 1<=m<=5000 1<=m<=5000 。分别表示房间数及门的数量。
接下来 m m m 行,每行四个数: i , j , C i j , C j i i,j,C_{ij},C_{ji} i,j,Cij,Cji
输出
输出文件包括一行,及最小的环需要经过的房间数。
保证不会出现自环及重边。
样例输入
4 4
1 2 -10 3
1 3 1 -10
2 4 -10 -1
3 4 0 -3
样例输出
4
样例解释
1 → 3 → 4 → 2 → 1 1\rightarrow 3\rightarrow 4\rightarrow 2\rightarrow 1 1→3→4→2→1 为最小的符合题意的环长度为 4. 4. 4.
数据范围
对
30
%
30\%
30% 的数据,
n
<
=
10
;
n<=10;
n<=10;
对
60
%
60\%
60% 的数据,,
n
<
=
100
;
n<=100;
n<=100;
对
100
%
100\%
100% 的数据,
n
<
=
300
;
n<=300;
n<=300;
思路
这道题就是爆搜加剪枝。
就枚举第一个碰到环的位置,然后直接跑 dfs ,如果跑回了第一个碰到环的位置就表示形成了环。在跑的同时维护路径的权值和,如果环的权值和大于 0 0 0 ,就拿答案与环的大小取最小值。
但是这样会超时,要剪枝:
- 当当前链的长度已经超过答案,就直接退出(这个很显然)
- 当权值和变成负的,就立刻退出。
(因为如果这个环的边的权值和大于 0 0 0 ,那必然存在一个开始的点,使在转了一圈的全部过程的时候,权值和都保持大于 0 0 0 的状态)
然后好像就没了。
代码
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
struct node {
int x, to, nxt;
}e[100001];
int n, m, w, x, y, z, le[301], KK;
int dep[301], ans = 2147483647;
bool in[301];
void add(int x, int y, int z) {
e[++KK] = (node){z, y, le[x]}; le[x] = KK;
}
void dfs(int now, int num, int l, int yeye) {
if (l < 0 || num > ans) return ;//剪枝
if (now == yeye && num && l > 0) {//有环
ans = min(ans, num);
return ;
}
in[now] = 1;
for (int i = le[now]; i; i = e[i].nxt)
if (!in[e[i].to] || e[i].to == yeye)
dfs(e[i].to, num + 1, l + e[i].x, yeye);
in[now] = 0;
}
int main() {
scanf("%d %d", &n, &m);//读入
for (int i = 1; i <= m; i++) {
scanf("%d %d %d %d", &w, &x, &y, &z);//读入
if (y + z > 0) {//可以在两条路中反复横跳
printf("2");
return 0;
}
add(w, x, y);//建图
add(x, w, z);
}
for (int i = 1; i <= n; i++) {//枚举环中第一个遇到的点
memset(in, 0, sizeof(in));
dfs(i, 0, 0, i);
}
printf("%d", ans);//输出
return 0;
}