UESTC 1638 红藕香残玉簟秋,轻解罗裳,独上兰舟。

本文介绍了一种利用差分约束系统求解点权极小与极大值的方法,通过构建图模型并运用SPFA算法求解最短路径与最长路径问题,实现了在特定条件下寻找各点权值的上下界。

题目链接:http://acm.uestc.edu.cn/#/problem/show/1638

题意:
给定n个点(点权未知)和m条信息:u的权值>=v的权值+w
求点权的极小解和极大解(无解则输出-1)

极小解即每个点的点权可能的最小值
极大解即每个点的点权可能的最大值

数据范围:
1<=n<=100000
1<=m<=1000000
0<=w<=100
点权为0到100之间的整数

题解:
差分约束。
求最大值,跑最短路,建一条从v到u权值为w的边。
求最小值,跑最长路,建一条从u到v权值为-w的边。



#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5+7;
const int maxm = 1e6+7;
struct edge{
    int v, w, next;
    edge(int v=0, int w=0, int next=0):v(v),w(w),next(next){}
}E1[2*maxm], E2[2*maxm];
int head1[maxn], head2[maxn], cnt1, cnt2;
int n, m, cnt[maxn], inq[maxn], mx[maxn], mi[maxn], Q[maxn];
void init(){
    memset(head1, -1, sizeof(head1));
    memset(head2, -1, sizeof(head2));
    cnt1 = cnt2 = 0;
}
void add(int u, int v, int w, int op)
{
    if(op&1){
        E1[cnt1]=edge(v,w,head1[u]), head1[u]=cnt1++;
    }
    else{
        E2[cnt2]=edge(v,w,head2[u]), head2[u]=cnt2++;
    }
}
bool spfa1(){
    int top = 0;
    memset(mi, -1, sizeof(mi));
    mi[0] = 0;
    cnt[0] = 1;
    inq[0] = 1;
    Q[top++] = 0;
    while(top){
        int u = Q[--top]; inq[u] = 0;
        for(int i = head1[u]; ~i; i = E1[i].next){
            int v = E1[i].v, w = E1[i].w;
            if(mi[v] < mi[u] + w){
                mi[v] = mi[u] + w;
                if(inq[v]) continue;
                if(cnt[v] > n) return 0;
                cnt[v]++;
                inq[v] = 1;
                Q[top++] = v;
            }
        }
    }
    return 1;
}
bool spfa2(){
    int top = 0;
    memset(mx, 0x3f, sizeof(mx));
    memset(inq, 0, sizeof(inq));
    memset(cnt, 0, sizeof(cnt));
    mx[0] = 100;
    cnt[0] = 1;
    inq[0] = 1;
    Q[top++] = 0;
    while(top){
        int u = Q[--top]; inq[u] = 0;
        for(int i = head2[u]; ~i; i=E2[i].next){
            int v = E2[i].v, w = E2[i].w;
            if(mx[v] > mx[u] + w){
                mx[v] = mx[u] + w;
                if(inq[v]) continue;
                if(cnt[v] > n) return 0;
                cnt[v]++;
                inq[v] = 1;
                Q[top++] = v;
            }
        }
    }
    for(int i=1; i<=n; i++){
        if(min(mi[i],mx[i])<0 || max(mi[i],mx[i])>100) return 0;
    }
    return 1;
}
int main()
{
    init();
    scanf("%d %d", &n,&m);
    for(int i = 1; i <= m; i++){
        int u, v, w;
        scanf("%d %d %d", &u,&v,&w);
        add(v, u, w, 1);
        add(u, v, -w, 2);
    }
    for(int i = 1; i <= n; i++){
        add(0, i, 0, 1);
        add(0, i, 0, 2);
    }
    if(spfa1()&&spfa2())
    {
        for(int i = 1; i <= n; i++){
            printf("%d %d\n", mi[i], mx[i]);
        }
    }
    else{
        puts("-1");
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值