题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=4773
233可能我是因为没看懂倍增的做法才去学的二分做法的,本题我们是要求最小的答案,答案是客观已经存在的(不像dp,你需要做一些选择),显然是满足单调性的,因此我们可以二分,再利用DFS-SPFA找负环的方法,我们限制SPFA搜索的层数,不就是限制点数的范围了吗?
(数据小我猜你也卡不了)
AC Code:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#define rg register
#define il inline
#define maxn 505
#define ll long long
#define eps 1e-8
#define lid id << 1
#define rid (id << 1) | 1
#define rep(a,b,c) for (rg int a = 1 ; a <= c ; a += b)
using namespace std;
il int read(){rg int x = 0 , w = 1;rg char ch = getchar();while (ch < '0' || ch > '9'){if (ch == '-') w = -1;ch = getchar();}while (ch >= '0' && ch <= '9'){x = (x << 3) + (x << 1) + ch - '0';ch = getchar();}return x * w;}
int head[500005] , cnt , n , m , num[maxn] , dis[maxn];
int vis[500005] , vis0;
bool ok = 0;
struct edge{
int fr , to , next , v;
}e[500005];
void add(int u,int v,int w){
e[++cnt].to = v;
e[cnt].next = head[u];
head[u] = cnt;
e[cnt].v = w;
}
void spfa(int now , int depth , int lmt){
if (ok) return;
for (rg int i = head[now] ; i ; i = e[i].next){
rg int to = e[i].to;
if (dis[to] >= dis[now] + e[i].v){
if (vis[to] == vis0) {ok = 1 ; return;}
if (depth == lmt) return;
dis[to] = dis[now] + e[i].v;
vis[to] = vis0;
spfa(to , depth + 1 , lmt);
vis[to]--;
}
}
}
bool check(int mid){
for (rg int i = 1 ; i <= n ; ++i){
ok = 0;
++vis0;
memset(dis , 0 , sizeof(dis)); // be careful!
vis[i] = vis0;
spfa(i , 1 , mid);
if (ok) return 1;
}
return 0;
}
int main(){
n = read() , m = read();
rg int u , v , w;
for (rg int i = 1 ; i <= m ; ++i){
u = read() , v = read() , w = read();
add(u , v , w);
//if (w >= 0 ) add(v , u , (double)w);
}
if (!check(n)) {cout << "0";return 0;}
rg int l = 1 , r = n , ans = 9999999;
while (l <= r){
int mid = (l + r) >> 1;
if (check(mid)) ans = mid , r = mid - 1;
else l = mid + 1;
}
cout << ans;
return 0;
}