版权声明:转载请声明出处,谢谢支持 https://blog.csdn.net/Dreamstar_DS/article/details/82825406
题目链接:https://vjudge.net/problem/POJ-3621
(个人比较喜欢用vjudge)
顺便贴个LG3385负环板题(无向图)的代码,以供参考
#include<bits/stdc++.h>
#define rg register
#define il inline
#define maxn 200005
#define ll long long
#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[maxn] , cnt , n , m , num[maxn] , q[maxn << 5] , dis[maxn];
bool vis[maxn];
struct edge{
int fr , to , next , v;
}e[maxn << 1];
void add(int u,int v,int w){
e[++cnt].to = v;
e[cnt].next = head[u];
head[u] = cnt;
e[cnt].v = w;
}
bool spfa(int s){
rg int l = 1 , r = 0;
memset(vis , 0 , sizeof(vis));
memset(num , 0 , sizeof(num));
memset(dis , 127 , sizeof(dis));
dis[s] = 0;
vis[s] = 1;
q[++r] = s;
num[s] = 1;
while (l <= r){
rg int now = q[l];
++l;
vis[now] = 0;
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){
dis[to] = dis[now] + e[i].v;
if (!vis[to]){
num[to]++;
if (num[to] > n) return 0;
q[++r] = to;
vis[to] = 1;
}
}
}
}
return 1;
}
int main(){
rg int t = read();
while (t--){
n = read() , m = read();
rg int u , v , w;
cnt = 0;
memset(head , 0 , sizeof(head));
for (rg int i = 1 ; i <= m ; ++i){
u = read() , v = read() , w = read();
add(u , v , w);
if (w >= 0 ) add(v , u , w);
}
bool flag = spfa(1);
if (flag) puts("N0");//真坑
else puts("YE5");//真坑
}
return 0;
}
新学了这类问题,了解到分数规划问题不少都是采用二分的方法,像此题我们是求所有环中sum{T[i] / F[i]}的MAX,我们就设k为二分答案,那么原式可以表示为sumT[i] - k * sumF[i] >= 0 , 由于两处都是sum,就相当于判断边权的正负性,就相当于我们要找一个正环。
正环咋找啊,我们将边权取负,不就是SPFA找负环了吗(interestring)
下面当然还有double二分的写法,都取mid,写eps等等
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#define rg register
#define il inline
#define maxn 200005
#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[maxn] , cnt , n , m , num[maxn] , q[maxn << 5] , p[maxn];
double val[maxn];
double dis[maxn];
bool vis[maxn];
struct edge{
int fr , to , next;
double v;
}e[maxn << 1];
void add(int u,int v,double w){
e[++cnt].to = v;
e[cnt].next = head[u];
head[u] = cnt;
e[cnt].v = w;
val[cnt] = w;
}
bool spfa(int s){
rg int l = 1 , r = 0;
memset(vis , 0 , sizeof(vis));
memset(num , 0 , sizeof(num));
memset(dis , 127 , sizeof(dis));
dis[s] = 0;
vis[s] = 1;
q[++r] = s;
num[s] = 1;
while (l <= r){
rg int now = q[l];
++l;
vis[now] = 0;
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){
dis[to] = dis[now] + e[i].v;
if (!vis[to]){
num[to]++;
if (num[to] > n) return 1;
q[++r] = to;
vis[to] = 1;
}
}
}
}
return 0;
}
bool check(double mid){
for (rg int i = 1 ; i <= m ; ++i) e[i].v = -p[e[i].to] + mid * val[i];//边权取负
return spfa(1);
}
int main(){
n = read() , m = read();
rg int u , v , w;
cnt = 0;
memset(head , 0 , sizeof(head));
for (rg int i = 1 ; i <= n ; ++i)
p[i] = read();
for (rg int i = 1 ; i <= m ; ++i){
u = read() , v = read() , w = read();
add(u , v , (double)w);
//if (w >= 0 ) add(v , u , (double)w);
}
double l = 0 , r = 10000 , ans;
while (r - l >= eps){
rg double mid = (l + r) / 2;
if (check(mid)) l = mid;
else r = mid;
}
printf("%.2lf\n" , l);
return 0;
}