差分约束

  • 解决不等式求最大/小值问题。(要求每个不等式只有两个变量,且系数一个为1,一个为-1)
  • 求两个变量差的最大值则间<=关系的边,跑最短路;
  • 求两个变量差的最小值则间>=关系的边,跑最长路;当然两边取-号转化为<=即可跑最短路,改变的仅仅是建图方式
  • 对于x2-x1<=c,建的边为x1->x2,权值为c
  • 用spfa,不能用dijkstra,因为要判负环,表示不等式无解。D[n]=inf表示有无穷解
  • 要求x3-x2最大值,则结果为dis[3]-dis[2]
  • 只能求两个变量系数为1的不等式组,其它情况适当转化,如区间和可以转化为差分

hdu6252:Subway Chasing

theme:n个车站,编号为1~n,两个人从1出发到n,B比A先出发x分钟,途中他们联系了m次,每次联系会得到两人的位置参数X,Y,P,Q,表示A位于车站X,Y之间,B位于车站P,Q之间,求两个车站间经过的时间,不存在输出Impossible.多种情况则输出满足0<ti≤2×10^9 的

1≤T≤30  1≤N,M≤2000  1≤X≤10^9  1≤A,B,C,D≤N  A≤B≤A+1  C≤D≤C+1

solution:差分约束求两个车站变量间的最小值。所以先找到变量间<=关系,建图跑spfs:

(1)若X==Y&&P==Q:则Q-X=x,则可以构造不等式:X-Q<=-x,P-Y<=x,建边Q->X,权值为-x,建边Y->P,权值为x,

(2)若X==Y&&P!=Q:则Q-X>x,P-Y<x,则X-Q<=-x-1,P-Y<=x-1,建边Q->X,权值为-x-1,建边Y->P,权值为x-1,

(3)若X!=Y&&P!=Q:则Q-X>x,P-Y<x,则X-Q<=-x-1,P-Y<=x-1,建边Q->X,权值为-x-1,建边Y->P,权值为x-1

(4)任意两点间的时间至少为1,所以i-(i-1)>=1

(5)为方便最后求解,我们加一个0节点,则求0节点到各个车站节点的最短路径即可

//差分约束
#include <bits/stdc++.h>
#include  <bitset>
#define ll long long
#define pr pair<int,int>
#define fi first
#define next fuck
#define se second
using namespace std;
const int MAXN=2010;
const int INF=0x3f3f3f3f;
struct Edge
{
    int v;
    int cost;
    Edge(int _v=0,int _cost=0):v(_v),cost(_cost) {}
};
vector<Edge>E[MAXN];
void addedge(int u,int v,int w)
{
    E[u].push_back(Edge(v,w));
}
bool vis[MAXN];//在队列标志
int cnt[MAXN];//每个点的入队列次数
int dist[MAXN];
bool SPFA(int start,int n)
{
    memset(vis,false,sizeof(vis));
    fill(dist,dist+n+1,INF);
    memset(cnt,0,sizeof(cnt));

    vis[start]=true;
    dist[start]=0;
    queue<int>que;
    while(!que.empty())
        que.pop();
    que.push(start);
    cnt[start]=1;
    while(!que.empty())
    {
        int u=que.front();
        que.pop();
        vis[u]=false;
        for(int i=0; i<(int)E[u].size(); i++)
        {
            int v=E[u][i].v;
            if(dist[v]>dist[u]+E[u][i].cost)
            {
                dist[v]=dist[u]+E[u][i].cost;
                if(!vis[v])
                {
                    vis[v]=true;
                    que.push(v);
                    if(++cnt[v]>n)
                        return false;
//cnt[i]为入队列次数,用来判定是否存在负环回路
                }
            }
        }
    }
    return true;
}
int n,m,x;

int main()
{
    int ca,cat = 1;
    scanf("%d",&ca);
    while(ca--)
    {
        scanf("%d%d%d",&n,&m,&x);
        for(int i =0; i<=n + 1; i++)
        {
            E[i].clear();
        }
        for(int i = 1; i<=n; i++)
        {
            if(i < n)
                addedge(i+1,i,-1);
            addedge(0,i,0);
        }
        for(int i = 0; i<m; i++)
        {
            int a,b,c,d;
            scanf("%d%d%d%d",&a,&b,&c,&d);
            if(a  == b)
            {
                if( c ==  d)
                {
                    addedge(d,a,-x);
                    addedge(b,c,x);
                }
                else
                {
                    addedge(d,a,-x-1);
                    addedge(b,c,x-1);
                }
            }
            else
            {
                addedge(d,a,-x-1);
                addedge(b,c,x-1);
            }

        }
        printf("Case #%d:",cat++);
        if(SPFA(0,n+1))
        {
            for(int i = 2; i<=n; i++)
            {
                printf(" %d",dist[i] - dist[i-1]);
            }
        }
        else
            printf(" IMPOSSIBLE");
        printf("\n");
    }
    return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值