hdu 6252 Subway Chasing (差分约束)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6252

 

题意:给出n个点,i-1到i的距离是不确定的,给出x代表两个人的距离,现在给出m条约束条件,每次给出A,B,C,D代表第一个人在区间(A,B)段,第二个人在区间(C,D)段,两个人的距离始终是x保持不变,求出一组每两个点距离都符合的可行解

数据范围:1≤T≤30,1≤N,M≤2000,1≤X≤1e9,1≤A,B,C,D≤N,A≤B≤A+1,C≤D≤C+1

 

差分约束算法:可以解决y-x<=常数的问题,那么对于y-x>=常数可以变成x-y<=-常数,对于y-x<常数可以变成y-x<=常数-1,对于y-x=常数可以变成y-x<=常数&&x-y<=常数,那么按照减数向被减数连一条权值为常数的边,再定义一个超级源点向每个点连一条权值为0的边跑spfa的最短路dis数组里储存的便是答案,所有的dis数组中的值都加一个常数就是另一组解

 

思路:对于m条约束每次,c-b<=x建边,d-a>=x建边,若是a==b&&c==d,那么就是c-a==x建边,然后因为每两个连续的点的距离大于等于1,所以a[i]-a[(i-1)]>=1建边,最后再建一个超级源点(我选的n)对所有点连一条权值为0的边跑spfa即可dis数组中的差值就是答案。

#include <bits/stdc++.h>
using namespace std;
const int N=5e4+5;
const int INF=0x7fffffff;
struct p{int to,val;};
vector<p>G[N];
int n,m,t,x,dis[N],cnt[N];
bool vis[N];
void spfa(){
    memset(vis,0,sizeof(vis));
    memset(cnt,0,sizeof(cnt));
    for(int i=0;i<n;i++)dis[i]=INF;
    vis[n]=1;dis[n]=0;cnt[n]=1;
    queue<int>Q;
    while(!Q.empty())Q.pop();
    Q.push(n);
    bool flag=1;
    while(!Q.empty()){
        int u=Q.front();
        Q.pop();
        vis[u]=0;
        for(int i=0;i<G[u].size();i++){
            int to=G[u][i].to;
            if(dis[to]>dis[u]+G[u][i].val){
                dis[to]=dis[u]+G[u][i].val;
                if(!vis[to]){
                    vis[to]=1;
                    Q.push(to);
                    if(++cnt[to]>n){flag=0;break;}
                }
            }
        }
        if(flag==0)break;
    }
    if(flag==0)printf(" IMPOSSIBLE\n");
    else{
        for(int i=1;i<n;i++)printf(" %d",dis[i]-dis[i-1]);
        puts("");
    }
}
int main(){
    int cas=1;
    scanf("%d",&t);
    while(t--){
        scanf("%d%d%d",&n,&m,&x);
        for(int i=0;i<=n;i++)G[i].clear();
        for(int i=1;i<n;i++){
            G[i].push_back(p{i-1,-1});///反向连-1的边
            G[n].push_back(p{i,0});
        }///把点n设为超级源点
        for(int i=1;i<=m;i++){
            int a,b,c,d;
            scanf("%d%d%d%d",&a,&b,&c,&d);
            a--,b--,c--,d--;
            if(a==b&&c==d){
                G[c].push_back(p{a,-x});
                G[a].push_back(p{c,x});
            }
            else{
                G[d].push_back(p{a,-(x+1)});
                G[b].push_back(p{c,(x-1)});
            }
        }
        printf("Case #%d:",cas++);
        spfa();
    }
    return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值