YbtOj练习:二分5 飞离地球

除看这道题,以为就是很简单的二分+判断负环

但是数次0分告诉我哪有你想的那么简单

我们在求最短路的过程中,应该把那些不同时满足1.与起点联通2.与终点联通的点删除。  一旦我们把这些点考虑进去,且这些点上还有负环时,对答案的影响就是致命的。

比如说这种情况

 

 而如果终点不满足上述条件,我们就可以直接输出-1了。

#include<bits/stdc++.h>
using namespace std;
const int N=105,M=10005,inf=0x3f3f3f3f;
int h[N],e[M],ne[M],w[M];
int tot,n,m,T,dis[N];
bool vis[N],useful[N];//useful表示是否同时满足两个约束条件 
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9')
    {
        if(ch=='-') f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')
    {
        x=x*10+ch-'0';
        ch=getchar();
    }
    return x*f;
}
inline void add(int a,int b,int c)
{
    ne[++tot]=h[a];
    e[tot]=b;
    w[tot]=c;
    h[a]=tot;
}
inline void dfs(int x)
{
    vis[x]=1;
    for(int i=h[x];i;i=ne[i])
    {
        int t=e[i];
        if(!vis[t])dfs(t);
    }
}
inline bool judge(int now,int x)  //判断负环 
{
    vis[now]=1;
    for(int i=h[now];i;i=ne[i])
    {
        int t=e[i];
        if(dis[t]>dis[now]+w[i]+x&&useful[t]) 
        {
            if(vis[t]) return true;  //被重复更新,出现负环 
            dis[t]=dis[now]+w[i]+x;
            if(judge(t,x)) return true;
        }
    }
    vis[now]=0;
    return false;
}
inline void SPFA(int x)
{
    memset(dis,0x3f,sizeof(dis));
    memset(vis,0,sizeof(vis));
    queue<int> Q;
    Q.push(1);dis[1]=0;vis[1]=1;
    while(!Q.empty())
    {
        int tmp=Q.front();Q.pop();vis[tmp]=0;
        for(int i=h[tmp];i;i=ne[i])
        {
            int t=e[i];
            if(dis[t]>dis[tmp]+w[i]+x&&useful[t])
            {
                dis[t]=dis[tmp]+w[i]+x;
                Q.push(t);
                vis[t]=1;
            }
        }
    }
}
inline bool check(int x)
{
    for(int i=1;i<=n;i++)
    if(useful[i])
    {
        memset(dis,0,sizeof(dis));//判断负环不需要把dis初始化成正无穷 
        memset(vis,0,sizeof(vis));
        if(judge(i,x)) return false;
    }
    SPFA(x);
    if(dis[n]>=0&&dis[n]<=inf) return true;
    return false;
}
int main()
{
    T=read();
    while(T--)
    {
        int ans=0;
        int l=-1e6,r=1e6;
        memset(h,0,sizeof(h));
        memset(useful,0,sizeof(useful));
        tot=0;
        n=read();m=read();
        for(int i=1;i<=m;i++)
        {
            int a=read(),b=read(),c=read();
            add(a,b,c);
        }
        memset(vis,0,sizeof(vis));
        dfs(1);
        for(int i=1;i<=n;i++)
        if(vis[i]) useful[i]=1;
        for(int i=1;i<=n;i++)
        if(useful[i]) 
        {
            memset(vis,0,sizeof(vis));
            dfs(i);
            if(!vis[n]) useful[i]=0;
        }
        if(!useful[n])   //特判 
        {
            printf("-1\n");
            continue;
        }
        while(l<r)
        {
            int mid=l+r>>1;
            if(check(mid)) r=mid,ans=dis[n];
            else l=mid+1;
        }
        printf("%d\n",ans);
    }
    return 0;
}

 

posted @ 2020-08-12 10:42  Gold_stein  阅读(377)  评论(0编辑  收藏  举报