BZOJ_1486_[HNOI2009]最小圈_01分数规划
Description
Input
Output
Sample Input
4 5
1 2 5
2 3 5
3 1 5
2 4 3
4 1 3
1 2 5
2 3 5
3 1 5
2 4 3
4 1 3
Sample Output
3.66666667
二分答案,边权减去答案,判负环即可。
然而spfa判负环会T掉,于是我使用了dfs判负环的方法。
dfs判负环代码:
void dfs(int x) { vis[x]=1; int i; for(i=head[x];i&&!ok;i=nxt[i]){ if(dis[to[i]]>dis[x]+cost[i]){ dis[to[i]]=dis[x]+cost[i]; if(vis[to[i]]){ ok=1;return ; } dfs(to[i]); } } vis[x]=0; }
不断更新最小值,直到更新了一圈回来,则说明有负环存在。
总之是比spfa快到不知哪里去。
dis数组清零即可。
代码:
#include <stdio.h> #include <string.h> #include <algorithm> using namespace std; #define N 3050 #define M 10050 #define du double #define eps 1e-9 int head[N],to[M],nxt[M],val[M],cnt,n,m; int dep[N],inq[N],Q[N],l,r,ok,vis[N]; du dis[N],cost[M]; inline void add(int u,int v,int w) { to[++cnt]=v;nxt[cnt]=head[u];head[u]=cnt;val[cnt]=w; } void dfs(int x) { vis[x]=1; int i; for(i=head[x];i&&!ok;i=nxt[i]){ if(dis[to[i]]>dis[x]+cost[i]){ dis[to[i]]=dis[x]+cost[i]; if(vis[to[i]]){ ok=1;return ; } dfs(to[i]); } } vis[x]=0; } bool check(du x) { int i; for(i=1;i<=m;i++) cost[i]=val[i]-x; for(i=1;i<=n;i++) dis[i]=vis[i]=0; for(i=1,ok=0;i<=n;i++) { dfs(i); if(ok) return 1; } return 0; } int main() { scanf("%d%d",&n,&m); int i,x,y,z; for(i=1;i<=m;i++) { scanf("%d%d%d",&x,&y,&z); add(x,y,z); } du L=-100000,R=100000; while(R-L>eps) { du mid=(L+R)*0.5; if(check(mid)) R=mid; else L=mid; } printf("%.8lf ",L); }