HDU1384差分约束
Posted hesorchen
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDU1384差分约束相关的知识,希望对你有一定的参考价值。
题目
在一个非负半轴上,给出n个限制条件,每个条件格式为l r k。表示在闭区间 [ l , r ] [l,r] [l,r]上,至少要有k个点被染色。问,要同时满足这n个限制条件,最少要染色多少个点。
思路
可以用 D [ i ] D[i] D[i]表示闭区间 [ 0 , i ] [0,i] [0,i]有多少个点被染色。这样对于每个输入的限制条件,就有 D [ r ] − D [ l − 1 ] > = k D[r]-D[l-1]>=k D[r]−D[l−1]>=k。因为输入的是闭区间,所以左端点要减一。另外0减一可能会出现-1,因此把输入的值都做加一处理。
需要注意的是,只有题目输入的限制条件还不足以解出这题,例如根据题目转换出的差分约束系统是
{ x 2 − x 1 > = c 1 x 4 − x 3 > = c 2 \\begin{cases} x_2-x_1>=c_1\\\\\\\\ x_4-x_3>=c_2 \\end{cases} ⎩⎪⎨⎪⎧x2−x1>=c1x4−x3>=c2
虽然可以正确的解出四个变量的一组取值,然而在这个题目实例中,显然还有隐藏的限制条件: 0 < = x 3 − x 2 < = 1 0<=x_3-x_2<=1 0<=x3−x2<=1,如果忽略了这些条件,那么局部约数条件组合在一起的差分约束系统可能违背了这题的题目背景(在一个点上染色贡献出多个点)。
代码
#include <bits/stdc++.h>
using namespace std;
const int N = 5e4 + 10;
struct node
{
int v, next, w;
} edge[N * 4];
int head[N];
int ct = 1;
void add(int u, int v, int w)
{
edge[ct].v = v;
edge[ct].w = w;
edge[ct].next = head[u];
head[u] = ct++;
}
int dis[N];
bool vis[N];
void spfa(int beg)
{
memset(dis, -0x3f3f3f3f, sizeof dis);
dis[beg] = 0;
queue<int> q;
q.push(beg);
while (q.size())
{
int u = q.front();
// cout << u << endl;
q.pop();
vis[u] = 0;
for (int i = head[u]; i; i = edge[i].next)
{
int v = edge[i].v;
int w = edge[i].w;
if (dis[v] < dis[u] + w)
{
dis[v] = dis[u] + w;
// cout << dis[v] << endl;
if (!vis[v])
{
q.push(v);
vis[v] = 1;
}
}
}
}
}
int main()
{
int n;
while (~scanf("%d", &n))
{
memset(head, 0, sizeof head);
memset(vis, 0, sizeof vis);
ct = 1;
int mx = 0;
int mn = 0x3f3f3f3f;
for (int i = 1; i <= n; i++)
{
int u, v, w;
scanf("%d %d %d", &u, &v, &w);
++v, ++u;
add(u - 1, v, w);
mn = min(u, mn);
mx = max(mx, v);
}
for (int i = mn; i <= mx; i++) //隐藏的约束条件
{
add(i - 1, i, 0);
add(i, i - 1, -1);
}
for (int i = 1; i <= mx; i++)
add(mx + 1, i, 0);
spfa(mx + 1);
cout << dis[mx] << endl;
}
return 0;
}
以上是关于HDU1384差分约束的主要内容,如果未能解决你的问题,请参考以下文章
POJ 1384 Intervals (线性差分约束,根据不等式建图,然后跑spfa)