一个用二分答案,找一个环的问题
因为有负数,一开始怕负数会影响答案(其实并不影响),所以给每条边都 + 上了边权值的最大值,但是最后求出来的答案精度会有所偏差,为什么?
附上两份代码(一个正常,一个加上 max)和样例
2 2
1 2 -2.9
2 1 -3.1
/*
简化题意,给定带权有向图,求平均边权(总边权/边数)最小的环。
一脸疑惑の看了半天式子,
为什么+1e7 之后 减去 1e7 不行=_=
精度不够!
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<stack>
#include<map>
#include<algorithm>
#include<cmath>
#include<vector>
using namespace std;
const double lim=1e-10;
const int M=1e5+9;
struct node{
int last;
int to;
double dis;
}e[M<<1];
int head[M],cnt;
double ans;
double dis[M];
int vis[M];
int n,m;
void add(int from,int to,double dis)
{
e[++cnt].last=head[from];
e[cnt].to=to;
e[cnt].dis=dis;
head[from]=cnt;
}
void clear()
{
for(int i=1;i<=n;i++)
dis[i]=vis[i]=0;
}
bool search(int u,double x)
{
vis[u]=true;
for(int i=head[u];i;i=e[i].last)
{
int v=e[i].to;
double w=e[i].dis;
if(dis[v]>dis[u]+w-x)
{
dis[v]=dis[u]+w-x;
if(vis[v]) return true;
if(search(v,x)) return true;
}
}
vis[u]=false;
return false;
}
bool check(double x)
{
clear();
for(int i=1;i<=n;i++)
if(search(i,x)) return true;
return false;//一个else 毁全家
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
int x,y;
double z;
scanf("%d%d%lf",&x,&y,&z);
add(x,y,z);
}
double l=-1e7+9,r=1e7+9;
while(r-l>=lim)
{
double mid=(l+r)/2.0;
if(check(mid))
{
ans=mid;
r=mid;
}
else l=mid;
}
printf("%.8lf",ans);
return 0;
}
/*
简化题意,给定带权有向图,求平均边权(总边权/边数)最小的环。
一脸疑惑の看了半天式子,
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <stack>
#include <map>
#include <algorithm>
#include <cmath>
#include <vector>
using namespace std;
const double lim = 1e-6;
const int N = 3e3 + 9;
const int M = 1e4 + 9;
struct node {
int last;
int to;
double dis;
} e[M * 2];
int head[N], cnt;
double ans;
double dis[N];
int vis[N];
int n, m;
void add(int from, int to, double dis) {
e[++cnt].last = head[from];
e[cnt].to = to;
e[cnt].dis = dis;
head[from] = cnt;
}
void clear() {
memset(dis, 0, sizeof(dis));
memset(vis, 0, sizeof(vis));
}
bool search(int u, double x) {
vis[u] = true;
for (int i = head[u]; i; i = e[i].last) {
int v = e[i].to;
double w = e[i].dis;
if (dis[v] > dis[u] + w - x) {
dis[v] = dis[u] + w - x;
if (vis[v])
return true;
if (search(v, x))
return true;
}
}
vis[u] = false;
return false;
}
inline bool check(double x) {
clear();
for (int i = 1; i <= n; i++)
if (search(i, x))
return true;
return false;
}
int main() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= m; i++) {
int x, y;
double z;
scanf("%d%d%lf", &x, &y, &z);
add(x, y, z + 1e7);
}
double l = 0, r = 2e7;
while (r - l > lim) {
double mid = (l + r) / 2.0;
if (check(mid)) {
ans = mid;
r = mid - lim;
} else
l = mid + lim;
}
printf("%.8lf", (ans - 10000000 * 1.0));
return 0;
}