http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1340
设x为环线的长度,要判断某个特定的x是否可行,不难将题目转为差分约束模型,用最短路求解,每个限制条件对应图中一条边,可行当且仅当图中没有负环。
如果x是整数,用最短路可以构造出整数解,因此现在需要对所有x同时判断,求出x的可行域,再求整数解个数。
由于边权是关于x的一次函数,且一次项系数绝对值<=1,可以用Bellman-Ford算法处理,此时一个点w到源点的距离dist(w)被表示为关于x的函数dist(w,x),且这个函数可以表示为一系列一次函数取min。最后判负环的时候相当于求 对每条长度为e(w,u)的边w->u都满足dist(w,x)+e(w,u)-dist(u,x)>=0 的 x的取值范围。
时间复杂度O(Tn^2m)。
#include<bits/stdc++.h> typedef long long i64; const i64 inf=1ll<<50; int T,n,m1,m2,ep; i64 l[55][111]; void mins(i64&a,i64 b){if(a>b)a=b;} i64 up(i64 A,i64 B){ if(B<0)B=-B,A=-A; i64 C=A/B; return C+(C*B<A); } i64 dn(i64 A,i64 B){ if(B<0)B=-B,A=-A; i64 C=A/B; return C-(C*B>A); } struct pos{ i64 x; int y; bool operator<(const pos&w)const{return x<w.x;} }ps[300007]; int pp; void ins(i64 L,i64 R){ ps[pp++]=(pos){L,1}; ps[pp++]=(pos){R+1,-1}; } struct ln{ i64 k,b,l,r; i64 at(i64 x){ return k*x+b; } void chk(ln w){ i64 L=std::max(l,w.l),R=std::min(r,w.r); if(L>R)return; w.k=k-w.k; w.b=b-w.b; if(w.at(L)>=0){ if(w.at(R)>=0)ins(L,R); else ins(L,dn(-w.b,w.k)); }else if(w.at(R)>=0)ins(up(-w.b,w.k),R); } bool cmp(ln&w){ return at(l)>=w.at(l); } void cut(ln&w){ i64 K=k-w.k,B=b-w.b; r=dn(-B,K); w.l=r+1; } }v1[1007],v2[1007]; void push(ln*a,int&ap,ln w){ for(;ap&&a[ap].cmp(w);--ap); if(ap)a[ap].cut(w); a[++ap]=w; } struct edge{ int x,y,a,b; void upd(){ for(int i=0;i<=n*2;++i)if(i+b>=0&&i+b<=n*2)mins(l[y][i+b],l[x][i]+a); } void chk(){ int p1=0,p2=0; for(int i=n*2;i>=0;--i){ if(l[x][i]<inf/2)push(v1,p1,(ln){i-n+b,l[x][i]+a,n,inf}); if(l[y][i]<inf/2)push(v2,p2,(ln){i-n,l[y][i],n,inf}); } int i1=1,i2=1; while(i1<=p1&&i2<=p2){ v1[i1].chk(v2[i2]); if(v1[i1].r<=v2[i2].r)++i1;else ++i2; } } }e[1007]; void ae(int a,int b,int d,int k){ e[ep++]=(edge){a,b,d,k}; } int main(){ for(scanf("%d",&T);T;--T){ scanf("%d%d%d",&n,&m1,&m2); ep=0; for(int i=0;i<n;++i){ for(int j=0;j<=n*2;++j)l[i][j]=inf; } l[0][n]=0; for(int i=0;i<n;++i){ int a=i,b=(i+1)%n,d=1; ae(b,a,-d,(a>b)); } for(int i=1,a,b,d;i<=m1;++i){ scanf("%d%d%d",&a,&b,&d); ae(b,a,-d,(a>b)); } for(int i=1,a,b,d;i<=m2;++i){ scanf("%d%d%d",&a,&b,&d); ae(a,b,d,-(a>b)); } for(int t=1;t<n;++t){ for(int i=0;i<ep;++i)e[i].upd(); } pp=0; for(int i=0;i<ep;++i)e[i].chk(); std::sort(ps,ps+pp); i64 ans=0; for(int i=0,s=0;i<pp;++i){ s+=ps[i].y; if(s==ep)ans+=ps[i+1].x-ps[i].x; } if(ans>inf/4)ans=-1; printf("%lld\n",ans); } return 0; }