UVA-11478 Halum (差分约束系统)

题目大意:一张n个节点的有向带边权图,每次操作能任选一个节点v个一个整数d,使以v为终点的边权值都减少d,以v为起点的边权值都增加d,求若干次操作后的最小边权值的非负最大值。

题目分析:用sum[i]表示作用在节点i上的所有d之和,则对于边a->b,操作若干次后的权值为w(a,b)+sum[a]-sum[b],假设最小边权值的最大值为x,则有sum[b]-sum[a]≤w(a,b)-x。这样的所有m条边构成一个差分约束系统。二分枚举x,求解即可。

代码如下:

# include<iostream>
# include<cstdio>
# include<queue>
# include<cstring>
# include<algorithm>
using namespace std;

const int INF=1<<30;
struct Edge
{
    int to,nxt,w;
};
Edge e[3500];
int cnt,n,head[3000],inq[505],vis[505],dist[505];

void add(int u,int v,int w)
{
    e[cnt].to=v;
    e[cnt].w=w;
    e[cnt].nxt=head[u];
    head[u]=cnt++;
}

bool bellman_ford(int M)
{
    queue<int>q;
    for(int i=1;i<=n;++i){
        vis[i]=inq[i]=1;
        dist[i]=0;
        q.push(i);
    }
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        inq[u]=0;
        for(int i=head[u];i!=-1;i=e[i].nxt){
            int v=e[i].to;
            if(dist[v]>dist[u]+e[i].w-M){
                dist[v]=dist[u]+e[i].w-M;
                if(!inq[v]){
                    inq[v]=1;
                    q.push(v);
                    if(++vis[v]>n-1)
                        return true;
                }
            }
        }
    }
    return false;
}

int main()
{
    int m,a,b,c;
    while(~scanf("%d%d",&n,&m))
    {
        cnt=0;
        memset(head,-1,sizeof(head));
        int maxn=0;
        while(m--)
        {
            scanf("%d%d%d",&a,&b,&c);
            add(a,b,c);
            maxn=max(maxn,c);
        }
        if(bellman_ford(1))
            printf("No Solution
");
        else if(!bellman_ford(maxn+1))
            printf("Infinite
");
        else{
            int l=1,r=maxn;
            while(l<r){
                int x=l+(r-l+1)/2;
                if(bellman_ford(x))
                    r=x-1;
                else
                    l=x;
            }
            printf("%d
",l);
        }
    }
    return 0;
}

  

原文地址:https://www.cnblogs.com/20143605--pcx/p/4909135.html