给出N个整数区间[ai,bi],并且给出一个约束ci,( 1<= ci <= bi-ai+1),使得数组Z在区间[ai,bj]的个数>= ci个,求出数组Z的最小长度。
分析:
对于给定的条件,假设S[j]为数组Z在[0,j]上的包含的元素个数,则我们可以根据条件得到S[bi+1] - S[ai] >= ci ===> S[ai] - S[bi+1] <= -ci,而且我们在根据隐含的条件1 >= S[j+1]-S[j] >= 0,可以得到一个差分约束系统。但是题目要求我们的是求约束图的最长路径,则我们应该反过来做,令S[N] = 0,从终点开始求。
若要满足不等式V(a)<=V(b)+W(b,a),则可以从b到a连一条权为W(b,a)的边,求最短路得之。
从b到a的最短路意味着满足所有不等式的a-b之最大值。
即a-b<=w =》b-a>=-w,所有-w就是所求的ans
CODE:
/*差分约束*/ /*AC代码:375ms*/ #include <iostream> #define MAXN 50005 #define INF 0x7fffffff using namespace std; struct edge { int to,w,next; }E[3*MAXN]; int head[MAXN],ecnt; int Stack[MAXN],dis[MAXN],cnt[MAXN]; bool Instack[MAXN]; int N,top,l,r; void Insert(int from,int to,int w) { E[ecnt].to=to; E[ecnt].w=w; E[ecnt].next=head[from]; head[from]=ecnt++; } bool Relax(int from,int to,int w) { if(dis[to]>dis[from]+w) { dis[to]=dis[from]+w; return true; } return false; } void Init() { int i,u,v,w; memset(head,-1,sizeof(head));ecnt=0; l=INF;r=-INF; //S[u]-S[v+1]<=-w for(i=1;i<=N;i++) { scanf("%d%d%d",&u,&v,&w); if(u<l) l=u; if(v+1>r) r=v+1; Insert(v+1,u,-w); } for(i=l;i<r;i++) { Insert(i+1,i,0);//S[i]-S[i+1]<=0 Insert(i,i+1,1);//S[i+1]-S[i]<=1 } } void SPFA(int s,int e) { int i,u,v; top=0; memset(Instack,false,sizeof(Instack)); for(i=s;i<=e;i++) dis[i]=INF; dis[e]=0;//注意要从e开始 Stack[++top]=e; Instack[e]=true; while(top) { u=Stack[top--]; Instack[u]=false;//出栈 for(i=head[u];i!=-1;i=E[i].next) { v=E[i].to; if(Relax(u,v,E[i].w)&&!Instack[v]) { Instack[v]=true; Stack[++top]=v; } } } } int main() { while(scanf("%d",&N)!=EOF) { Init(); SPFA(l,r); printf("%d\n",-dis[l]); //必有解,无需判负环 } return 0; }