题目链接:UVa 515 King
差分约束系统。
如果一个系统由n个变量和m个约束条件组成,其中每个约束条件形如xj-xi<=bk(i,j∈[1,n],k∈[1,m]),则称其为差分约束系统(system of difference constraints)。亦即,差分约束系统是求解关于一组变量的特殊不等式组的方法。
求解差分约束系统,可以转化成图论的单源最短路径(或最长路径)问题。
观察xj-xi<=bk,会发现它类似最短路中的三角不等式d[v]<=d[u]+w[u,v],即d[v]-d[u]<=w[u,v]。因此,以每个变量xi为结点,对于约束条件xj-xi<=bk,连接一条边(i,j),边权为bk。我们再增加一个源点s,s与所有定点相连,边权均为0。对这个图,以s为源点运行Bellman-ford算法(或SPFA算法),最终{d[ i]}即为一组可行解。(来自百度百科)
本题利用前n个元素的和作为节点,即设s[i] = a[1] + a[2] + …a[i]。
有a[si] + a[si+1] + … + a[si + ni] = s[si + ni] - s[si - 1],所以如果a[si] + a[si+1] + … + a[si + ni] < k 则 s[si + ni] - s[si - 1] < k <= k - 1;如果a[si] + a[si+1] + … + a[si + ni] > k 则 s[si - 1] - s[si + ni] < -k <= -k - 1;
需要注意的地方时这个题本身是存在0这个点的(我刚开始把0作为添加的源点果断错了),因为需要表示s[1]。
增加的源点作为第n + 1个点,那么总共是有n + 2个点的,所以用SPFA判断存在负环应该是一个点进入队列的次数大于等于n + 2。
#include <iostream>
#include <cstring>
#include <stdio.h>
#include <queue>
using namespace std;
const int MAX_N = 200 + 10;
int head[MAX_N],d[MAX_N],cnt[MAX_N],vis[MAX_N];
const int INF = (1 << 30);
struct Edge
{
int v, w, next;
};
Edge edge[MAX_N];
int n, m, _count;
void addEdge(int u, int v, int w)
{
edge[_count].v = v;
edge[_count].w = w;
edge[_count].next = head[u];
head[u] = _count++;
}
bool SPFA()
{
memset(vis,0,sizeof(vis));
memset(cnt,0,sizeof(cnt));
for(int i = 0;i <= n;i++)
d[i] = INF;
d[n + 1] = 0;
queue<int> Q;
Q.push(n + 1);
cnt[n + 1]++;
while(!Q.empty())
{
int u = Q.front();
Q.pop();
vis[u] = false;
for(int e = head[u]; e != -1; e = edge[e].next)
{
if(d[edge[e].v] > d[u] + edge[e].w)
{
d[edge[e].v] = d[u] + edge[e].w;
if(!vis[edge[e].v])
{
Q.push(edge[e].v);
vis[edge[e].v] = true;
cnt[edge[e].v]++;
if(cnt[edge[e].v] >= n + 2)// 0 ~ n + 1 共有n + 2个点
return false;
}
}
}
}
return true;
}
int main()
{
while(scanf("%d", &n), n)
{
scanf("%d", &m);
int s, len, k;
char str[10];
_count = 0;
memset(head, -1, sizeof(head));
for(int i = 0; i <= n; i++)
addEdge(n + 1, i, 0);//添加从n + 1 到所有点的路径,设置边权为0
for(int i = 1; i <= m; i++)
{
scanf("%d%d%s%d", &s, &len, str, &k);
if(str[0] == 'g')//将大于转换为小于等于
addEdge(s + len, s - 1, -k - 1);
else//将小于转化为小于等于
addEdge(s - 1, s + len, k - 1);
}
if(!SPFA())
printf("successful conspiracy\n");
else
printf("lamentable kingdom\n");
}
return 0;
}
本文介绍了如何使用差分约束系统解决UVa515King问题,通过构建特殊的不等式组并将其转化为图论中的单源最短路径问题来求解。特别地,解释了如何利用Bellman-Ford算法或SPFA算法来判断是否存在负环,进而确定解的存在性。
1398

被折叠的 条评论
为什么被折叠?



