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+1Output 对于每个测试用例,输出一行包含“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
思路
题意:两个人乘一个由n站的地铁出发去公司,出发点为s = 1, 终点e = 2, 第一个人先出发k分钟,之后另一个人在出发(这里我们应该默认当它们都坐上地铁以后们的相对距离差是不会在改变的,
他们之间所差的时间也是不变的,始终是k
),在这个期间它们进行了m次交流,每次交流包含 a、b、c、d ,4个站点,其中a、b表示第2个人为与a -b 站之间,若果a == b,那么第二人正好在 a或b站点上, 同了c、d表示第2个人位置,问相邻站点之间的所用的时间是多少思路:明显差分约束,去求解不等式,首先这一题要求
ti <= 1e9
,那么为了不超过时间限制,我们应该求最小时间差 --> 那么转化的图上就是求最大距离,首先我们将所有的不等式转化为 a >= b + val,这样的形式,如果不是的话就移项转化成这样的
,建立b->a 边全为val 的边,对于 a > b + val -->我们转化为 a >= b + val + 1 这个时候我们 建立一条 b->a 权值为val + 1的边; 对于 a < b + val -->我们转化为 a < b + val - 1 --> 之后在同时在同时移动左右项转化为 :b >= a - (val - 1) 对于这样的情况我们建立一条 a ->b 权值为 -(val - 1) 的边;对于 b - a == val的情况我们可以把它转化成两个不等式:b - a >= val 、b - a <= val 在它们最终经过目标形式转化之后变成:b >= a + val (建立a -> b 边权为val的边)、a >= b -val (建立b->a 边权为 -val的边)
那么对于本题 如果 (a != b || c != d) ->我们可以发掘出两个不等式:c - b < k 、d - a > k ---->对这两个不等式进行目标转还建边, 如果(a == b && c== b) 的话 这个时候 c - b == k --->根据相等的情况进行目标转化 建边就行了
代码
#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <queue>
#include <cmath>
#include <stack>
using namespace std;
#define INF 0x3f3f3f3f
#define mod 1000000009
const int mxn = 5e6;
struct Edge
{
int v, w, next;
} edge[mxn];
int n, m, k;
int head[mxn];
int cnt = 0;
int use[mxn];
int dis[mxn];
int tim[mxn];
void Add(int u, int v, int w)
{
edge[++ cnt] = (Edge){ v, w, head[u] };
head[u] = cnt;
}
bool Spfa(int s)
{
for(int i = 1; i <= n; i ++)
use[i] = 0, tim[i] = 0, dis[i] = -INF;
dis[s] = 0;
queue<int> q;
q.push(s);
int u, v, w;
while(! q.empty())
{
u = q.front(), q.pop();
use[u] = 0;
tim[u] ++;
if(tim[u] > n) return false;
for(int i = head[u]; i; i = edge[i].next)
{
v = edge[i].v;
w = edge[i].w;
if(dis[v] < dis[u] + w)
{
dis[v] = dis[u] + w;
if(! use[v])
{
q.push(v);
use[v] = 1;
}
}
}
}
return true;
}
void init()
{
cnt = 0;
for(int i = 0; i <= n; i ++)
head[i] = 0;
}
int main()
{
/* freopen("A.txt","r",stdin); */
int t, Case = 1;
scanf("%d", &t);
while(t --)
{
scanf("%d %d %d", &n, &m, &k);
init();
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(c, b, -k + 1); //c - b < k -> c - b <= k - 1 -> b >= c - k + 1
Add(a, d, k + 1); //d - a > k -> d - a >= k + 1
}
else //a == b && c == d c - b == k --> (c - b >= k && c - b <= k)
{
Add(a, d, k);
Add(d, a, -k);
}
}
//增加超级源点或者相邻车站的时间间隔肯定>= 1
for(int i = 2; i <= n; i ++)
Add(i-1, i, 1);
printf("Case #%d:", Case ++);
if(Spfa(1))
{
for(int i = 2; i <= n; i ++)
printf(" %d", dis[i] - dis[i - 1]);
printf("\n");
}
else
printf(" IMPOSSIBLE\n");
}
return 0;
}
总结
- 对与这样的题,我们首相要根据题意弄懂要求的是最短距离还是最大距离
- 如果是让求的是最小值那么我们要把所有的不等式转化为:a >= b + val;若是让求的是最大值我们要把所有的不等式转化为为:a <= b + va ,然后相应边。
- 一般题目会包含隐含的限制(隐含的不等式条件)
- 之后还要建立一个超级源点保持图的连通性,(当然如过我们能通过 找到发掘 隐含的限制条件,以保证图的连通性,就可以不用建立超级源点)