您的位置:首页 > 其它

UVA 515 - King 差分约束系统

2011-03-17 00:00 232 查看
差分约束系统(system of difference constraints)是线性规划问题的一种。在一个差分约束系统中,线性规划矩阵A的每一行包含一个1和一个-1,A的所有其他元素都为0。因此,由Ax≤b给出的约束条件是m个差分约束集合,其中包含n个未知元。每个约束条件为如下形式的简单线性不等式:
  xj-xi≤bk
  其中,1≤i, j≤n,1≤k≤m。

  例如:寻找一个5维向量x = ( xi )以满足:



  这一问题等价于找出未知量x1,x2,x3,x4,x5,满足以下8个差分约束条件:



  该问题的一个解为x = ( -5, -3, 0, -1, -4),这可以直接代入每个不等式得到验证。实际上,该问题有多个解。另一个解为x' = ( 0, 2 , 5, 4, 1),这两个解是有联系的:x'中的每个元素比x中的相应元素大5。这一事实并不是巧合:若x = ( x1, x2, …, xn )是一个差分约束系统Ax≤b的一个解,d为任意常数。则x + d = ( x1 + d, x2 + d, …, xn + d )也是该系统Ax≤b的解。
  证明:对于每个xi和xj,有( xj + d ) - ( xi + d ) = xj - xi。因此,若x满足Ax≤b,则x + d也同样满足。

  通过观察,不难发现:每一个约束条件的不等式与求单源最短路算法中的松弛操作极为类似。
  将图形理论与差分约束系统Ax≤b加以联系:m * n的线性规划矩阵A可被看作是n个顶点,m条边的图的关联矩阵的转置。对于i = 1, 2, …, n,图中的每一个顶点vi对应着n个未知量的一个xi。图中的每个有向边对应于两个未知量的m个不等式的其中一个。

  这样,通过求解新建立图的单源最短路经问题就能得到差分约束系统的一组解:
  为保证图的连通,在图中引入附加节点vs使图中每个顶点vi都能从vs可达,并设弧( vs, vi )的权w( vs, vi ) = 0。对于每一个差分约束xj - xi bk(注意是小于等于符号),则弧( xi, xj )的权w( xi, xj ) = bk。
  初始化dis[ vs ] = 0,dis[ i ] = ∞。
  求解以vs为源点的单源最短路径。

  需要说明的是:如果图中存在负权回路,则该差分约束系统不存在可行解。

  对于采用单源最短路径的算法,我选择了SPFA算法。原因有二:
  1、SPFA算法同Bellman-Ford算法一样允许图中有负权边;
  2、相比Bellman-Ford算法,SPFA算法判负权回路的效率更高。

  关于SPFA算法在差分约束系统中判负权回路的问题:
  与Bellman-Ford算法类似,在一个含有n个顶点的图中,若某条边松弛操作的次数超过了n - 1次,则表明该图中存在负权回路;不同的地方只是Bellman-Ford算法通过第n次循环做的这个判断,而SPFA算法是通过某个顶点的入队次数做的判断。
  值得注意的是:虽然顶点vs是在求解差分约束系统中引入的附加顶点,但在构建出的图中,是运用单源最短路算法求解以vs为源点的单源最短路,所以若线性规划矩阵A有n列,则构建图中存在负权回路的判断条件是:图中某条弧松弛操作的次数超过了n次。

以上转自博客:落花

UVA king 程序代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<set>
#include<vector>
#include<string>
#include<algorithm>
using namespace std;
#define MAXN 220
#define INF (1 << 30)
int u[MAXN], v[MAXN], w[MAXN], d[MAXN];
int m, n;
int bellman_ford()
{
for(int i = 0; i <= n + 1; d[i++] = INF);
d[0] = 0;
for(int i = 1; i <= n + 1; i++){
for(int j = 0; j <= (m + n); j++){
if(d[v[j]] > d[u[j]] + w[j])
d[v[j]] = d[u[j]] + w[j];
}
}
for(int j = 0; j <= (m + n); j++)
if(d[v[j]] > d[u[j]] + w[j])    return 0;
return 1;
}
int main()
{
//freopen("input.txt", "r", stdin);
char s[10];
int b, e, k;
memset(u, 0, sizeof(u));
memset(v, 0, sizeof(v));
memset(w, 0, sizeof(w));
while(scanf("%d", &n) == 1, n){
scanf("%d", &m);
for(int i = 0; i < m; i++){
scanf("%d %d %s %d", &b, &e, s, &k);
if(s[0] == 'g'){
u[i] = b + e + 1;
v[i] = b;
w[i] = -k - 1;
}else {
u[i] = b;
v[i] = b + e + 1;
w[i] = k - 1;
}
}
for(int i = 1, j = m; i <= n + 1; j++, i++){
u[j] = 0;
v[j] = i;
w[j] = 0;
}
if(bellman_ford()) printf("lamentable kingdom/n"); else printf("successful conspiracy/n");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: