世界真的很大
一些条件限制的题目可以用SPFA来转化成差分约束系统
能想到这个的却是不错,但是千万不要考虑漏了
差分约束在某些题目中除了题目条件还有一些隐藏条件
如果不处理这些隐藏条件,差分约束系统跑出来的结果可能会自相矛盾
这道题就是如此
看题先:
description:
给定n个闭合的整数间隔[ai,bi]和n个整数c1,…,cn。
写一个程序:
从标准输入读取间隔数,它们的终点和整数c1,…,cn,
对于每个i = 1,2,…,n,计算具有至少具有间隔[ai,bi]的公共元素的整数集合Z的最小大小,
将答案写入标准输出。
input:
输入的第一行包含整数n(1 <= n <= 50000) - 间隔数。 以下n行描述间隔。 输入的第(i + 1)行包含由单个空格分开的三个整数ai,bi和ci,并且使得0 <= ai <= bi <= 50000和1 <= ci <= bi-ai + 1。
output:
对于每个i = 1,2,…,n,输出包含恰好等于组Z的至少ci元素的最小尺寸的整数,其中间距为[ai,bi]。
首先一个套路性的东西就是[L,R]数字个数可以转化成[1,R]的个数减去[1,L-1]的个数,倒不是说一定是这样,但起码看到应该有这样的思路
然后每一个条件限制就变成了:[1,R]-[1,L-1] > = ci
有n组这样的式子,差分约束系统还是比较显然的
然后就按差分约束系统建边,由于范围不会超过5e5,直接用L,R来当编号就行了,直接用SPFA跑最长路,dis[maxn]就是答案
当然不会这么简单,这样跑出来样例的结果是5,为什么会这样呢?
然后把每一个数的dis输出来,dis[7]是4,然而dis[8]是1。。
自相矛盾了
之所以会这样,是因为我们直接按照题目所给的信息建边,而在题目中,7和8没有给出的关系,但是[1,8]怎么着也是应该大于[1,7]的
但是在差分约束系统中我们没有加入这个限制
加入之后,我们就相当于保证了8比7大,看似毫无问题,交了一波恭喜WA
为什么会这样呢?理论上来讲不该有问题啊,我们保证了小区间一定比大区间小啊?
当自己的理解已经到瓶颈时,优先确认一波代码有没有什么大错误,恰恰是没有的。那么只能说,对题意理解不深
再看一下题
我们要求的是整数集合
嗯
什么是集合?
集合中元素貌似。。。不可重吧?
我们保证了[1,8]比[1,7]大,但我们没有保证大多少,[1,8]比[1,7]大最多只能大1,因为8这个数在集合里可以选且只能选一次
即dis[8]-dis[7] < = 1
而我们之前的差分约束系统没有考虑这个条件
交了一波
稳稳AC
总结一下,做差分约束问题时,由于方法大家都知道,不就是SPFA嘛。出题人要考你,只能考条件的转化。
所以差分约束的题,条件肯定是十分重要的,认真分析有没有隐藏的限制条件
完整代码:
#include<stdio.h>
#include<cstring>
#include<queue>
using namespace std;
const int INF=0x3f3f3f3f;
struct edge
{
int v,last,w;
}ed[1000010];
queue <int> state;
int n,num=0,S=INF,maxn=0,dis[500010],se[500010],mrk[500050],in[500050],head[500050];
void add(int u,int v,int w)
{
num++;
ed[num].v=v;
ed[num].w=w;
ed[num].last=head[u];
head[u]=num;
}
void SPFA()
{
for(int i=1;i<=maxn;i++) dis[i]=-INF;
state.push(S);
dis[S]=0,se[S]=1;
while(!state.empty())
{
int u=state.front();
state.pop(),se[u]=0;
for(int i=head[u];i;i=ed[i].last)
{
int v=ed[i].v;
if(dis[v]<dis[u]+ed[i].w)
{
dis[v]=dis[u]+ed[i].w;
if(!se[v])
{
se[v]=1;
state.push(v);
}
}
}
}
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add(u-1,v,w);
S=min(S,u-1),maxn=max(maxn,v);
}
for(int i=S;i<maxn;i++)
add(i,i+1,0),add(i+1,i,-1);
SPFA();
printf("%d\n",dis[maxn]);
return 0;
}
/*
Whoso pulleth out this sword from this stone and anvil is duly born King of all England
*/
嗯,就是这样