1. 程式人生 > >BZOJ1486: [HNOI2009]最小圈

BZOJ1486: [HNOI2009]最小圈

【傳送門:BZOJ1486


簡要題意:

  給出一張n個點m條邊的連通圖,求出這個圖中,所有環中,環上的邊權和/環上的點數的最小值


題解:

  直接01分數規劃二分答案,然後類似與SPFA的dfs判負環就行了


參考程式碼:

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#define Maxn 3100
#define eps 1e-9
using namespace
std; struct node{int x,y,next;double c;}a[21000];int len,last[Maxn]; void ins(int x,int y,double c){a[++len]=(node){x,y,last[x],c};last[x]=len;} double d[Maxn]; bool v[Maxn]; bool dfs(int x) { v[x]=true; for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(d[y]-(d[x]+a[k].c)>-eps) {
if(v[y]==true) return true; else { d[y]=d[x]+a[k].c; if(dfs(y)==true) return true; } } } v[x]=false; return false; } int n; bool check(double c) { for(int i=1;i<=len;i++) a[i].c-=c; bool
bk=false; memset(v,false,sizeof(v)); memset(d,0,sizeof(d)); for(int i=1;i<=n;i++) { d[i]=0.0; if(dfs(i)==true){bk=true;break;} } for(int i=1;i<=len;i++) a[i].c+=c; return bk; } int main() { int m; scanf("%d%d",&n,&m); len=0;memset(last,0,sizeof(last)); for(int i=1;i<=m;i++) { int x,y;double c; scanf("%d%d%lf",&x,&y,&c); ins(x,y,c); } double l=-10000000.0,r=10000000.0,ans; while(r-l>eps) { double mid=(l+r)/2.0; if(check(mid)==true) { ans=mid; r=mid; } else l=mid; } printf("%.8lf\n",ans); return 0; }