题意就是给出每段至少有几个数如ai到bi至少用ci个数....问整个集合至少需要多少个数才能满足所有的条件...ci <= bi - a1 + 1...
转化一下...Sk代表不大于k有多少个数...那么题目的条件就转化为一组 Sbi - S(ai-1) >= ci了..
分析题目给出的不等式...以及题目的"至少需要"..也就是要求的是一组最小非负解...
传统的用SPFA解差分约束..是给出的一组或者说要化成一组 a - b <= k 的形式...然后来构边.. a为终点,b为起点..权值为k...用SPFA求出的是确定一个数后的最大解..
但这道题是要求的是最小解...这里就要更加的深入理解用SPFA解差分约束了..
之所以能用SPFA来解差分约束...就是SPFA在relax时是
d [ line.end ] >= d [ line.start ] + line.wight
更新完后..所有的 d [ i ] 都会满足这个条件..
再看差分约束系统每一项的形式
a - b <= k 稍微转化一下..
就是 b>=a-k ...
如果把 b作为 line.end..a作为 line.start..k作为line.wight...那么就和SPFA的relax一模一样...
SPFA作完后能保证所有的 d [ line.end ] >= d [ line.start ] + line.wight ...自然就能保证所有的不等式成立...
所以将每一项的 b 作为线段的终点,a作为线段的起点,k作为线段的权值...定一个源点(相当于给某一个点一个确定值)然后做一次SPFA..就能得到一组满足所有条件的解(这里不讨论存在负环的情况)...并且这个解是确定了某个值后的最大一组解( 所有的和相加最大...这里还没理解...)..
回到这道题...给出的每一项是 a - b >=k 可以将两边同时乘负一得到 b - a <= -k 也可以干脆就把 SPFA 的Relax 改成d [ line.end ] <= d [ line.start ] + line.wight 来求解...因为同理a - b >=k 可以写成 b <= a + k.... 同样的b 作为线段的终点,a作为线段的起点,k作为线段的权值
我是用的后面一种方法...SPFA的Relax改了以后~~做出的一组解首先会是满足所有约束条件的...并且这组解是在确定了某个点的值下最小的一组解(和原始的那种正好相反)...这道题肯定就是把最小的点赋值为0然后来求..做出来直接就是题目所要求一组最小的非负解了...答案也就是在 d [ maxdata ] 里...
这道题有两个隐性条件一定要用上...第一个就是 Sk - S(k-1) >=0 相邻两个数的差是大于等于0的...Sk - S(k-1) <=1 相邻两个数的差是小于等于1的...要加上这些约束条件..也就是加上这些边..
题目的处理的方面...因为题目的数列是从0开始的...但在沟成约束条件是...如输入告诉说 1 到 3 至少有1个数..那转化成不等式应该是 S3 - S0 >=1...那如果给出的是 0 到 3 至少有一个数呢??难道 S3 - S-1 >=1 ??明显下标越界..所以干脆把数列向右平移一个单位..让其从1开始就行了...还有一点就是我在程序中用minnum和maxnum分别记录这组约束条件中出现的最小数和最小数,减少不必要的操作...
Runtime error的...要注意边的个数..不止题目给的50000...因为自己要构更多的边...就是那两个隐形条件的边...所以至少需要开150001的大小..
Progarm:
#include<iostream>
#include<queue>
#define MAXN 200001
#define oo 0x7F
using namespace std;
struct p1
{
int x,y,k,next;
}line[MAXN];
int i,n,m,link[MAXN],x,y,k,minnum,maxnum;
queue<int> myqueue;
int SPFA()
{
int i,k,h,d[MAXN];
bool used[MAXN];
while (!myqueue.empty()) myqueue.pop();
memset(d,-0x7F,sizeof(d));
memset(used,false,sizeof(used));
d[minnum]=0; myqueue.push(minnum);
while (!myqueue.empty())
{
h=myqueue.front();
myqueue.pop();
used[h]=false;
k=link[h];
while (k)
{
if (d[line[k].y]<d[h]+line[k].k)
{
d[line[k].y]=d[h]+line[k].k;
if (!used[line[k].y])
{
used[line[k].y]=true;
myqueue.push(line[k].y);
}
}
k=line[k].next;
}
}
return d[maxnum];
}
int main()
{
while (~scanf("%d",&n))
{
memset(link,0,sizeof(link));
memset(line,0,sizeof(line));
m=0;
minnum=oo; maxnum=-oo;
while (n--)
{
scanf("%d%d%d",&x,&y,&k);
y++;
if (x<minnum) minnum=x;
if (y>maxnum) maxnum=y;
m++;
line[m].x=x; line[m].y=y; line[m].k=k;
line[m].next=link[line[m].x]; link[line[m].x]=m;
}
int k;
for (i=minnum;i<maxnum;i++)
{
m++;
line[m].x=i+1; line[m].y=i; line[m].k=-1;
line[m].next=link[line[m].x]; link[line[m].x]=m;
m++;
line[m].x=i; line[m].y=i+1; line[m].k=0;
line[m].next=link[line[m].x]; link[line[m].x]=m;
}
printf("%d\n",SPFA());
}
return 0;
}