BZOJ1486:[HNOI2009]最小圈——题解

https://www.lydsy.com/JudgeOnline/problem.php?id=1486

https://www.luogu.org/problemnew/show/P3199

题面太鬼畜就不粘了。

这题唯一正确的解法是https://www.luogu.org/blog/user7868/solution-p3199虽然我看不懂。

当然为了AC这道题于是抛弃自己的灵魂写了dfs-spfa结果跑的飞快。

这样的题算是出锅了吧……

简单讲下做法,二分答案,对每条边减去这个答案搜负环,如果存在的话该答案合法,否则不合法。

#include<cmath>
#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef double dl;
const dl INF=1e7;
const dl eps=1e-9;
const int N=3e3+5;
const int M=1e4+5;
struct node{
    int to,nxt;
    dl w;
}e[M];
int cnt,head[N],n,m,sum[N];
bool vis[N],ok;
dl dis[N];
queue<int>q;
inline void add(int u,int v,dl w){
    e[++cnt].to=v;e[cnt].w=w;e[cnt].nxt=head[u];head[u]=cnt;
}
void spfa(int u){
    vis[u]=1;
    for(int i=head[u];i&&!ok;i=e[i].nxt){
        int v=e[i].to;dl w=e[i].w;
        if(dis[v]>=dis[u]+w){
            dis[v]=dis[u]+w;
            if(vis[v]||ok){ok=1;return;}
            spfa(v);
        }
    }
    vis[u]=0;
}
bool pan(dl delta){
    for(int i=1;i<=m;i++)e[i].w-=delta;
    for(int i=1;i<=n;i++)vis[i]=0,dis[i]=0;
    ok=0;
    for(int i=1;i<=n&&!ok;i++)
           spfa(i);
    for(int i=1;i<=m;i++)e[i].w+=delta;
    return ok;
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++){
        int u,v;dl w;
        scanf("%d%d%lf",&u,&v,&w);
        add(u,v,w);
    }
    dl l=-INF,r=INF;
    while(fabs(r-l)>eps){
        dl mid=(l+r)/2;
        if(pan(mid))r=mid;
        else l=mid;
    }
    printf("%.8lf\n",l);
    return 0;
}

+++++++++++++++++++++++++++++++++++++++++++

+本文作者:luyouqi233。               +

+欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/ +

+++++++++++++++++++++++++++++++++++++++++++

posted @ 2018-05-01 13:48  luyouqi233  阅读(202)  评论(0编辑  收藏  举报