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; }
渺渺时空,茫茫人海,与君相遇,幸甚幸甚