链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1486
题意:中文题,和上题相似,求的是sigma(c)/k最小的环,c是边的权值,k为选了多少点。
分析:
还是找简单还,证明在上一题。
如果一个比例L使得sigma(c)-L*K是个负权环,那么可能存在一个小于L的比例R使得sigma(c)-R*K是个负权环,这就是01分数规划的套路。
代码:
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<string>
#include<vector>
#include<queue>
#include<cmath>
#include<stack>
#include<set>
#include<map>
#define INF 0x3f3f3f3f
#define Mn 3010
#define Mm 2000005
#define mod 1000000007
#define CLR(a,b) memset((a),(b),sizeof((a)))
#define CLRS(a,b,Size) memset((a),(b),sizeof((a[0]))*(Size+1))
#define CPY(a,b) memcpy ((a), (b), sizeof((a)))
#pragma comment(linker, "/STACK:102400000,102400000")
#define ul u<<1
#define ur (u<<1)|1
using namespace std;
typedef long long ll;
const double eps=1e-9;
struct edge {
int v,next;
double w;
}e[Mm];
int head[Mn],tot;
void addedge(int u,int v,double w) {
e[tot].v=v;
e[tot].w=w;
e[tot].next=head[u];
head[u]=tot++;
}
int vis[Mn],st;
double dis[Mn];
bool dfs(int u,double x) {
vis[u]=st;
for(int i=head[u];~i;i=e[i].next) {
int v=e[i].v;
double w=e[i].w-x;
if(dis[v]>dis[u]+w) {
if(vis[v]==st) return true;
dis[v]=dis[u]+w;
if(dfs(v,x)) return true;
}
}
vis[u]=-1;
return false;
}
int n;
bool check(double x) {
CLR(vis,0);
CLR(dis,0);
for(st=1;st<=n;st++) {
if(vis[st]==0&&dfs(st,x)) return true;
}
return false;
}
int main() {
int m,u,v;
double w;
CLR(head,-1);
tot=0;
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++) {
scanf("%d%d%lf",&u,&v,&w);
addedge(u,v,w);
}
double l=-10000.0,r=10000.0;
while((r-l)>eps) {
double mid=(l+r)/2;
if(check(mid)) r=mid;
else l=mid;
}
printf("%.8f\n",r);
return 0;
}