2017 ccpc final J Subway Chasing(差分约束)

Subway Chasing HDU - 6252(差分约束)

题意:

有n个站。
有两个人A和B。(A先出发),x min后,B也出发了
有m次询问。
每次都
[ a,b ] 和 [c,d](abcd分别表示车站,且b<=a+1(d<=c+1))
找到一组满足的解。(每个车站的时间差)

思路:

差分约束。

反思

  1. 连边时,(由于是不等式)注意符号!!!!!!!
    一般dis[v]<=dis[u]+w;
    上面就是add(u,v,w)。
  2. 假如是<时,那么要转换成<=.方法是

边权w减少1.

  1. 假如是等式,那么要连双向边。
  2. 一般建立一个源点,其他点连接它。

AC

#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
#define For(i,x,y) for(int i=(x); i<=(y); i++)
#define fzhead EDGE(int _to, int _v, int _next)
#define fzbody to(_to), v(_v), next(_next)
#define mst(x,a) memset(x,a,sizeof(x))
using namespace std;
const int maxm=4e6+10;
const int maxn=2e3+10;
const int inf=0x3f3f3f3f;
struct EDGE{
    int to, v, next;
    EDGE(){}
    fzhead:fzbody{}
}e[maxm];
int cnt,n,m,x,w;
int dis[maxn],head[maxn],vis[maxn],fuhuan[maxn];
void add(int bg, int to, int val){
    e[++cnt]=EDGE(to,val,head[bg]);
    head[bg]=cnt;
}
bool spfa(int n){
    For(i,0,n)dis[i]=inf,vis[i]=0,fuhuan[i]=0;
    queue<int>q;
    q.push(0);//s=0;
    dis[0]=0;vis[0]=1;
    while(!q.empty()){
        int u=q.front();q.pop();
        vis[u]=0;
        for(int i=head[u]; i!=-1; i=e[i].next){
            int v=e[i].to,w=e[i].v;
            if(dis[v]>dis[u]+w){
                dis[v]=dis[u]+w;
               // cout<<"dis[u]  dis[v] "<<dis[u]<<' ';
               // cout<<dis[v]<<' '<<v<<endl;
                if(!vis[v]){
                    q.push(v);
                    vis[v]=1;
                    fuhuan[v]++;
                    if(fuhuan[v]>n+1)return false;//存在负环,无解。
                }
            }
        }
    }
    return true;
}
int main()
{
    int t,kase=0;scanf("%d", &t);
    while(t--){
        mst(head,-1);cnt=0;
        scanf("%d%d%d", &n, &m, &x);
        int a,b,c,d;
        for(int i=1; i<=m; i++){
            scanf("%d%d%d%d", &a, &b, &c, &d);
            if(a==b&&c==d){
                add(a,c,x);
                add(c,a,-x);//相等加两条边。
            }
            else{
                add(d,a,-x-1);
                add(b,c,x-1);
            }
        }
        /*
        for(int i=1; i<=n; i++){
            cout<<"e[i] "<<i<<"   ";
            for(int j=head[i]; j!=-1; j=e[j].next){
                cout<<e[j].to<<' ';
            }
            cout<<endl;
        }
        */
        for(int i=1; i<=n-1; i++)add(i+1,i,-1);
        for(int i=1; i<=n; i++)add(0,i,0);
        printf("Case #%d: ", ++kase);
        if(spfa(n)){
            for(int i=2; i<=n; i++)printf("%d ",dis[i]-dis[i-1]);
            puts("");
        }
        else printf("IMPOSSIBLE\n");
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值