bzoj2330

差分约束系统

1.du=dv 2.du+1<=dv 3.du>=dv 4.du>=dv+1 5.du<=dv

事实上,这道题希望总和最小,于是我们由小于号的左边连向右边,边权为常数项,跑最长路就可以了。

①:对于差分不等式,a - b <= c ,建一条 b 到 a 的权值为 c 的边,求的是最短路,得到的是最大值 
②:对于不等式 a - b >= c ,建一条 b 到 a 的权值为 c 的边,求的是最长路,得到的是最小值 
③:存在负环的话是无解 
④:求不出最短路(dist[ ]没有得到更新)的话是任意解 

这是差分约束的通常解法

#include<bits/stdc++.h>
using namespace std;
const int N = 100010;
struct edge {
    int nxt, to, w;
} e[N << 2];
int n, k, cnt = 1;
int vis[N], d[N], head[N], cir[N];
void link(int u, int v, int w)
{
    e[++cnt].nxt = head[u];
    head[u] = cnt;
    e[cnt].to = v;
    e[cnt].w = w;
}
int main()
{
    scanf("%d%d", &n, &k);
    for(int i = 1; i <= k; ++i)
    {
        int u, v, opt;
        scanf("%d%d%d", &opt, &u, &v);
        if(opt == 1)
        {
            link(u, v, 0);
            link(v, u, 0);
        }
        if(opt == 2) 
        {
            if(u == v)
            {
                puts("-1");
                return 0;
            }
            link(u, v, 1);
        }
        if(opt == 3) link(v, u, 0);
        if(opt == 4) 
        {
            if(u == v)
            {
                puts("-1");
                return 0;
            }
            link(v, u, 1);
        }
        if(opt == 5) link(u, v, 0);
    }
    queue<int> q;
    memset(d, 0x3f3f, sizeof(d));
    for(int i = n; i; --i) link(0, i, 1);
    d[0] = 0;
    q.push(0);
    while(!q.empty())
    {
        int u = q.front();
        q.pop();
        vis[u] = 0;
        for(int i = head[u]; i; i = e[i].nxt) if(d[e[i].to] > d[u] + e[i].w)
        {
            d[e[i].to] = d[u] + e[i].w;
            if(vis[e[i].to] == 0)
            {
                ++cir[e[i].to];
                if(cir[e[i].to] == n) 
                {
                    puts("-1");
                    return 0;
                }
                vis[e[i].to] = 1;
                q.push(e[i].to);
            }        
        }
    }
    long long ans = 0;
    for(int i = 1; i <= n; ++i) ans += d[i];
    printf("%lld\n", ans);
    return 0;
} 
View Code

 

转载于:https://www.cnblogs.com/19992147orz/p/7427986.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值