BZOJ_1486_[HNOI2009]最小圈_01分数规划

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

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\n",L);
}

 

posted @ 2018-04-02 22:43  fcwww  阅读(146)  评论(0编辑  收藏  举报