uva11478 图的边权变化求极值

题意:一个有向图,边权可正可负。对每个顶点,定义H(d)操作:入边边权全部-d,出边边权全部+d,问是否存在若干操作H(d)后,所有边权>=0,若不存在,输出“No Solution”,若存在,求最终最小边的最大值,如果最小边权的最大值可以任意大,输出”Infinite"

二分答案。题目转化为是否存在若干H操作,使得每条边的权值都>=x 。设对每个顶点u的H操作叠加后,为sum(u),则每条边<a,b>都有( sum(a)-sum(b)+w<a,b> )>=x ,转化为不等式组是否有解的问题,可用差分约束系统解决。


#include<stdio.h>
#include<iostream>
#include<string.h>
#include<algorithm>
#include<vector>
#include<queue>
#define ll long long
#define sf scanf
#define pf printf
#define INF 1<<29
#define maxn 100010
#define mem(a,b) memset(a,b,sizeof(a))
#define lowbit(x) x&(-x)
#define maxn 510
const ll mol=1000000007;
using namespace std;

int n,m,maxx;
struct node{
    int u,v,w;
}bian[maxn*maxn];
struct Edge{
    int to,w,next;
}edge[maxn*maxn];
int head[maxn],tot;
int inq[maxn],cnt[maxn],d[maxn];//是否在队列中&&进队次数&&最短路

void add(int u,int v,int w){
    edge[tot].to=v,edge[tot].next=head[u],edge[tot].w=w;
    head[u]=tot++;
}

void input(){
    maxx=-INF;
    for(int i=1;i<=m;i++){
        scanf("%d%d%d",&bian[i].u,&bian[i].v,&bian[i].w);
        maxx=max(maxx,bian[i].w);
    }
}

void build(int mid){
    mem(head,-1),tot=0;
    for(int i=1;i<=m;i++){
        add(bian[i].u,bian[i].v,bian[i].w-mid);
    }
}

bool negativecycle(){//spfa判断“有向图负圈”问题,并非求最短路
    queue<int> que;
    mem(inq,0),mem(cnt,0);
    for(int i=1;i<=n;i++) { inq[i]=1;d[i]=0;que.push(i); }//避免多个连通块存在,必须全部入队
    while(!que.empty()){
        int u=que.front();que.pop();inq[u]=0;
        for(int i=head[u];i!=-1;i=edge[i].next){
            int v=edge[i].to,w=edge[i].w;
            if(d[v]>d[u]+w){
                d[v]=d[u]+w;
                if(!inq[v]) { que.push(v);inq[v]=1;if(++cnt[v]>n) return true; }
            }
        }
    }
    return false;
}

int main(){
    //freopen("a.txt","r",stdin);
    while(scanf("%d%d",&n,&m)!=EOF){
        input();
        build(1);
        if(negativecycle()) { printf("No Solution\n"); continue; }
        build(maxx+1);
        if(!negativecycle()) { printf("Infinite\n"); continue; }
        int l=1,r=maxx+1,mid;
        while(l<r-1){//二分边界问题...仔细考虑
            int mid=l+(r-l)/2;
            build(mid);
            if(negativecycle()) r=mid;//r是不符合条件的情况!
            else l=mid;
        }
        printf("%d\n",l);
    }
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值