2010多校第一题 hdu3440House Man 差分约束系统

时间:2024-04-28 10:03:48

给我们n座房子,房子的高度各不相同, 从最低的房子开始, 每次跳到更高的房子, 跳n-1次最能跳到最高的房子了,但是每次跳跃的距离不能超过d

将这些房子在一维的方向上重新摆放(但是保持输入时的相对位置不变) , 使得最矮的房子和最高的房子水平距离最大

将房子的坐标设为xi,  n个变量, 和2(n-1)个约束关系,  典型的差分约束系统

高度相近的两个坐标(设为xi,xj)相减  abs(xi-xj) <= d,   要想办法去掉绝对值, 那么规定一律id大的减去id小的,那么结果就是正的

又需要保持输入的相对位置不变, 那么 x(i+1) - x(i) >=1,   因为要化为最短路 所以是  x(i) - x(i+1) <= -1

所以按照上面的分析构造图,然后跑一边最短路即可。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <algorithm>
#include <iostream>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <set>
#include <string>
#include <math.h>
using namespace std;
#pragma warning(disable:4996)
#pragma comment(linker, "/STACK:1024000000,1024000000")
typedef long long LL;
const int INF = << ;
/* */
const int N = + ;
struct Node
{
int id, height;
bool operator <(const Node &rhs)
{
return height < rhs.height;
}
}a[N];
struct Edge
{
int v, dist;
Edge(){}
Edge(int _v, int _dist) :v(_v), dist(_dist){}
bool operator<(const Edge&rhs)const
{
return dist > rhs.dist;
}
};
vector<Edge> g[N];
int dist[N];
bool vis[N];
int dij(int x, int y, int n)
{
for (int i = ; i <= n; ++i)
dist[i] = INF;
priority_queue<Edge> q;
Edge cur, tmp;
cur.dist = dist[x] = ;
cur.v = x;
q.push(cur);
while (!q.empty())
{
cur = q.top(); q.pop();
int u = cur.v;
if (dist[u] < cur.dist)//如果cur.dist < dist[u], 那么可以继续更新其他顶点, 代替了条件vis[u]
continue;
for (int i = ; i < g[u].size(); ++i)
{
int v = g[u][i].v;
if (dist[v] > dist[u] + g[u][i].dist)
{
tmp.dist = dist[v] = dist[u]+ g[u][i].dist;
tmp.v = v;
q.push(tmp);
}
}
}
return dist[y];
} int spfa(int x, int y, int n)
{
for (int i = ; i <= n; ++i)
dist[i] = INF;
queue<int> q;
q.push(x);
dist[x] = ;
while (!q.empty())
{
int u = q.front(); q.pop();
vis[u] = false;
for (int i = ; i < g[u].size(); ++i)
{
int v = g[u][i].v;
if (dist[v] > dist[u] + g[u][i].dist)
{
dist[v] = dist[u] + g[u][i].dist;//能更新就更新
if (!vis[v])//如果结点在队里里面,就不用重复入队了
{
q.push(v);
vis[v] = true;
}
}
}
}
return dist[y];
}
int main()
{ int n, d, t;
scanf("%d", &t);
for (int k = ; k <= t; ++k)
{
scanf("%d%d", &n, &d);
for (int i = ; i <= n; ++i)
g[i].clear();
for (int i = ; i <= n; ++i)
{
scanf("%d", &a[i].height);
a[i].id = i;
if (i != )
g[i].push_back(Edge(i-, -));
}
sort(a + , a + n + );
bool flag = true;
for (int i = ; i <= n; ++i)
{
if (abs(a[i].id - a[i - ].id) > d)
{
flag = false;
break;
}
g[min(a[i].id, a[i - ].id)].push_back(Edge(max(a[i].id, a[i - ].id), d));
}
printf("Case %d: ", k);
if (!flag)
puts("-1");
else
{
if (a[].id > a[n].id)
swap(a[].id, a[n].id);
printf("%d\n", spfa(a[].id, a[n].id,n));
} }
return ;
}

用最短路求出解后, 其它点与源点的差值最大。

用最长路求出解后,其它点与源点的差值最小。