正题
要你求一个环,使得边权除以点数最小。
就是求。
分数规划,二分k,令这个东西小于k
得到
判定问题成为一个判断图中是否有负环,新边的边权是原来的边权减去k。
判负环无高效算法,dfs即可。
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
using namespace std;
int n,m;
struct edge{
int x,y;
double c;
}p[10010];
struct new_edge{
int y,next;
double c;
}s[10010];
int first[3010],len=0;
bool vis[3010],flag,tf[3010];
double dis[3010];
void ins(int x,int y,double c){
len++;
s[len]=(new_edge){y,first[x],c};first[x]=len;
}
void dfs(int x){
for(int i=first[x];i!=0;i=s[i].next){
int y=s[i].y;
if(dis[y]>dis[x]+s[i].c){
if(tf[y]){
flag=true;
return ;
}
else{
dis[y]=dis[x]+s[i].c;
tf[x]=true;
dfs(y);
tf[x]=false;
if(flag) return ;
}
}
}
}
bool check(double x){
len=0;
memset(first,0,sizeof(first));
for(int i=1;i<=m;i++) ins(p[i].x,p[i].y,p[i].c-x);
memset(dis,63,sizeof(dis));
memset(vis,false,sizeof(vis));flag=false;
memset(tf,false,sizeof(tf));
for(int i=1;i<=n;i++)
if(!vis[i] && !flag) dis[i]=0,dfs(i);
return flag;
}
int main(){
scanf("%d %d",&n,&m);
for(int i=1;i<=m;i++) scanf("%d %d %lf",&p[i].x,&p[i].y,&p[i].c);
double l=-1e7,r=1e7;
while(r-l>=1e-9){
double mid=(l+r)/2;
if(check(mid)) r=mid;
else l=mid;
}
printf("%.8lf",l);
}
本文介绍了一种使用分数规划和二分查找方法求解最小环比问题的算法。通过将原问题转化为是否存在负环的判定问题,利用DFS进行搜索,最终找到使边权除以点数最小的环。
870

被折叠的 条评论
为什么被折叠?



