I - 动物狂想曲 (HDU-6252)(差分约束-最短路模型+判负环)

雷格西桑和路易桑是好朋友,在同一家公司工作。他们总是一起乘地铁去上班。他们的路线上有N个地铁站,编号从1到N。1站是他们的家,N站是公司。
有一天,雷格西桑起床晚了。当他来到车站时,路易桑已经离开X分钟了。雷格西桑非常着急,于是他开始和路易桑聊天,交流他们的位置。内容是雷格西桑在A站和B站之间,路易桑在C站和D站之间。
B等于A+ 1这意味着雷格西在A站和A+1之间, 或B等于A这意味着雷格西就是在车站A,反之亦然对于C和D同理.更重要的是,他们交流的时间不能早于雷格西桑的离开,也不能晚于路易桑的到来。
到达公司后,雷格西桑想知道相邻地铁站之间的间隔时间。请注意,每个站点的停止时间都被忽略了

Input

输入的第一行给出了测试用例的数量T.接下来是T组测试用例。每组测试用例以一行开始,由3个整数N、M和X组成,表示站点的数量、聊天内容的数量和雷格西桑与路易桑之间的分钟间隔。接下来是M行,每一行由4个整数A、B、C、D组成,表示每个聊天内容。
1≤T≤30
1≤N,M≤2000
1≤X≤109
1≤A,B,C,D≤N
A≤B≤A+1
C≤D≤C+1

Output

对于每个测试用例,输出一行包含“case #x: y”,其中x是测试用例编号(从1开始),y是格式为t1、t2、…、tN−1的站与站之间的分钟数。ti表示i站和i+1站之间的分钟数,若有多租解,输出其中一个满足0<ti≤2×109.如果没有解决方案,则输出“IMPOSSIBLE”。

Sample Input

2
4 3 2
1 1 2 3
2 3 2 3
2 3 3 4
4 2 2
1 2 3 4
2 3 2 3

Sample Output

Case #1: 1 3 1
Case #2: IMPOSSIBLE

Hint

在第二个测试案例中,当路易桑通过第三站时,雷格西桑还没有到达第二站。他们不能同时往返于第二站和第三站之间。

题意:现在有两个人A和B,他们相约一起坐地铁去上班。但是有一天A起来晚了,当A来到地铁站的时候,发现B已经离开X分钟了。于是他们开始通讯,互相报出自己所在的位置。这里有约束条件,当A在AB站点中间的时候,B在CD站点中间,(B一定等于A+1或者A,同理D也是)。更重要的是,他们交流的时间不能早于A的离开,也不能晚于B的到来。到达公司后,A想知道相邻地铁站之间的间隔时间。请注意,每个站点的停止时间都被忽略了。然后输出可能的间隔时间,如果不满足的话,输出“IMPOSSIBLE”。

思路:这道题的话,昨天晚上比赛的时候我看了一会,看出来是差分约束,但是题意有一些地方没有理解,所以就没继续推不等式。然后早上又读了几遍题,发现理解了一些,于是就推了一下不等式。不等式的话,需要分情况讨论。

第一种情况,当A==B && C==D的时候:

因为间隔距离是X分钟,所以可以推出不等式:

(1)C-B<=X  —>   C-B<=X

(2)D-A>=X  —>   A-D<=-X

第二种情况,当A==B && C!=D的时候;当A!=B && C!=D的时候;当A!=B &&C==D的时候,你会发现这三种情况是一样的。

所以推一下不等式:

(1)C-B<=X-1  —>   C-B<=X-1

(2)D-A>=X+1  —>   A-D<=-(X+1)

然后在读题的时候还会发现一个隐藏的约束条件,就是每两个相邻的车站之间至少需要1分钟的时间,所以推一下不等式:

dis[i]-dis[i-1]>=1 

 到这里,所有约束条件的不等式,我们都已经推完了,就这样建图加边的话,是肯定计算不出来的。因为我们没有保证图的连通性。所以我们需要建立一个超级源点,这里我以n为源点向每一个点都建立一条边来保证图的连通性。这样基本上所有的问题都解决了,然后我们套一下板子就可以AC这道题了。

AC代码:

#include <bits/stdc++.h>
typedef long long ll;
const int maxx=2010;
const int maxn=250010;
const int mod=1000000009;
const int inf=0x3f3f3f;
using namespace std;
struct node
{
    int v;
    int w;
    int next;
} edge[maxn];
int head[maxx],dis[maxx],num[maxx];
bool vis[maxx];
int cnt,n,m,x;
void add(int u,int v,int w)
{
    edge[cnt].v=v;
    edge[cnt].w=w;
    edge[cnt].next=head[u];
    head[u]=cnt++;
}
int spfa(int u)
{
    dis[u]=0;
    vis[u]=true;
    queue<int>q;
    q.push(u);
    while(!q.empty())
    {
        int x=q.front();
        q.pop();
        vis[x]=false;
        for(int i=head[x]; i!=-1; i=edge[i].next)
        {
            int v=edge[i].v;
            int w=edge[i].w;
            if(dis[v]>dis[x]+w)
            {
                dis[v]=dis[x]+w;
                if(!vis[v])
                {
                    vis[v]=true;
                    q.push(v);
                    if(num[v]++>n)
                        return 0;
                }
            }
        }
    }
    return 1;
}
void init()
{
    cnt=0;
    memset(head,-1,sizeof(head));
    memset(vis,false,sizeof(vis));
    memset(dis,0,sizeof(dis));
    memset(num,0,sizeof(num));
}
int main()
{
    int t,k=0;
    scanf("%d",&t);
    while(t--)
    {
        k++;
        init();
        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(d,a,-x);//d-a>=x
                add(b,c,x);//c-b<=x
            }
            else
            {
                add(d,a,-(x+1));//d-a>=x+1
                add(b,c,x-1);//c-b<=x-1
            }
        }
        for(int i=1; i<=n; i++) //超级源点
            add(n,i,0);
        for(int i=1; i<=n; i++)
            add(i,i-1,-1);//dis[i]-dis[i-1]>=1
        printf("Case #%d: ",k);
        if(spfa(n))
        {
            for(int i=2; i<=n; i++)
                printf("%d ",dis[i]-dis[i-1]);
            printf("\n");
        }
        else
            printf("IMPOSSIBLE\n");
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值