当前位置: 代码迷 >> 综合 >> BZOJ 1486 [HNOI2009] 最小圈
  详细解决方案

BZOJ 1486 [HNOI2009] 最小圈

热度:58   发布时间:2024-01-19 02:17:14.0

Description

Input

Output

Sample Input

4 5
1 2 5
2 3 5
3 1 5
2 4 3
4 1 3

Sample Output

3.66666667

HINT

Source

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

01分数规划+dfs/SPFA判负环~

根据01分数规划,我们二分寻找能使sum{(a[i]-b[i]*k)*x[i]}==0的k值,然后判负环,如果有负环,就增大k值。

注意这道题卡SPFA判负环,只能用类似于dfs+SPFA的判断方法,详见代码~


#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
#define eps 1e-10int n,m,x,y,fi[3001],w[20001],ne[20001],cnt;
bool b[3001];
double z,v[20001],ll[20001],mid,dis[3001];void add(int u,int vv,double val)
{w[++cnt]=vv;ne[cnt]=fi[u];fi[u]=cnt;v[cnt]=val;
}bool dfs(int u)
{b[u]=1;for(int i=fi[u];i;i=ne[i])if(dis[w[i]]>ll[i]+dis[u]){if(b[w[i]]){b[u]=0;return 1;}dis[w[i]]=ll[i]+dis[u];if(dfs(w[i])){b[u]=0;return 1;}}b[u]=0;return 0;
}bool che()
{memset(dis,0,sizeof(dis));for(int i=1;i<=cnt;i++) ll[i]=v[i]-mid;for(int i=1;i<=n;i++) if(dfs(i)) return 1;return 0; 
}int read()
{int totnum=0,f=1;char ch=getchar();while(ch<'0' || ch>'9') {if(ch=='-') f=-1;ch=getchar();}while(ch>='0' && ch<='9') {totnum=(totnum<<1)+(totnum<<3)+ch-'0';ch=getchar();}return totnum*f; 
}int main()
{n=read();m=read();for(int i=1;i<=m;i++) x=read(),y=read(),scanf("%lf",&z),add(x,y,z);double l=-1e7,r=1e7;while(r-l>=eps){mid=(l+r)*1.0/2.0;if(che()) r=mid;else l=mid; }printf("%.8lf\n",mid);return 0;
}