雷格西桑和路易桑是好朋友,在同一家公司工作。他们总是一起乘地铁去上班。他们的路线上有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;
}