>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;
}