Loading

题解:UVA1148 (差分约束)

题解:UVA1148 (差分约束)

链接

一道差分约束的好题。

不难发现,操作的顺序对答案没有影响。如果存在一条边 \((x,y)\) ,不妨设 \(S_x\) 为对 \(x\) 操作的 \(d\) 值之和,设 \(S_y\) 为对 \(y\) 操作的距离之和。

这个题的问法是经典的二分答案,我们假设现在二分到 \(mid\) ,如果 \(mid\) 合法,我们有:

\[S_y-S_x\ge w(x,y)-t \]

不难发现,这是一个差分约束。这个题就做完了。

注意,用 SPFA 判负环会 TLE ,所以我们最好用 DFS ,虽然最坏复杂度一样,但一般情况下不会到达最坏复杂度。

另一个是二分边界的问题,注意左界必须是 \(0\) 而不能是一个负数,因为有可能这张图全部都是 \(0\) 边。

代码:

#include<bits/stdc++.h>
#define dd double
#define ld long double
#define ll long long
#define int ll
#define uint unsigned int
#define ull unsigned long long
#define N 550000
#define M 300000
using namespace std;

const int INF=0x3f3f3f3f;

template<typename T> inline void read(T &x) {
    x=0; int f=1;
    char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c == '-') f=-f;
    for(;isdigit(c);c=getchar()) x=x*10+c-'0';
    x*=f;
}

struct edge{
    int to,next,w;
    inline void intt(int to_,int ne_,int w_){
        to=to_;next=ne_;w=w_;
    }
};
edge li[M];
int head[N],tail;

inline void add(int from,int to,int w){
    li[++tail].intt(to,head[from],w);
    head[from]=tail;
}

int n,m,d[N],s;
bool vis[N],app[N];

inline bool dfs(int k){
    vis[k]=1;
    for(int x=head[k];x;x=li[x].next){
        int to=li[x].to,w=li[x].w;
        if(d[to]>d[k]+w){
            d[to]=d[k]+w;
            if(vis[to]||dfs(to)) return 1;
        }
    }
    vis[k]=0;
    return 0;
}

inline bool check(int mid){
    for(int i=1;i<=m;i++) li[i].w-=mid;
    memset(vis,0,sizeof(vis));memset(d,INF,sizeof(d));d[s]=0;
    bool pd=dfs(s);
    for(int i=1;i<=m;i++) li[i].w+=mid;
    return 1^pd;
}

signed main(){
    // freopen("my.in","r",stdin);
    // freopen("my.out","w",stdout);
    bool op=1;
    while(scanf("%lld%lld",&n,&m)!=EOF){
        // if(n==-1&&m==-1) break;
        tail=0;memset(head,0,sizeof(head));
        memset(li,0,sizeof(li));memset(app,0,sizeof(app));
        for(int i=1;i<=m;i++){
            int from,to,w;read(from);read(to);read(w);
            add(from,to,w);
            app[from]=app[to]=1;
        }
        for(int i=1;;i++) if(!app[i]){s=i;break;}
        for(int i=1;i<=n;i++) add(s,i,0);
        int l=0,r=1e9;
        while(l<r){
            int mid=(l+r+1)>>1;
            if(check(mid)) l=mid;
            else r=mid-1;
        }
        if(l==0) printf("No Solution\n");
        else if(l==1e9) printf("Infinite\n");
        else printf("%lld\n",l);
    }
    return 0;
}
posted @ 2021-07-01 16:30  hyl天梦  阅读(39)  评论(0编辑  收藏  举报