差分约束系统
c[n]表示每个点的容量,d[n]表示前n个点的容量和,x[n]表示第n个点的人数,s[n]表示前n个点的人数和。
因为是求最大值,左右约束条件写成小于的形式,求最短路。
约束条件:
1.s[i]-s[i-1]<=c[i],即s[i]<=s[i-1]+c[i]; 增加边<i-1,i>=c[i];
2.s[i]-s[i-1]>=0, 即s[i-1]<=s[i]+0; 增加边<i,i-1>=0;
3,s[j]-s[i-1]>=k, 即s[i]<=s[j]-k; 增加边<j,i-1>=k;
4,s[j]-s[i-1]<=d[j]-d[i-1];即s[j]=s[i-1]+d[j]-d[i-1]; 增加边<i-1,j>=d[j]-d[i-1];
5,s[n]-s[0]=dis[n]>=0,即s[0]<=s[n]+0, 可以直接设置dis[n]=0;
初始设置dis[i]=INF,i(1,n-1);
//复杂度为O(mn),可以存在负边,要判断是否存在负权的圈 #include<iostream> #include<cstdio> #include<cstring> #define INF 0x7fffffff #define maxl 22222 #define maxn 1005 using namespace std; int d[maxn]={0}; struct Edg { int u,v,w; }; int dis[maxn]; Edg edg[maxl]; int n,m; int edgnum; void add(int u,int v,int w) { edg[edgnum].u=u; edg[edgnum].v=v; edg[edgnum].w=w; edgnum++; } bool bellman_ford() { int t,u,v,w; for(int i=1;i<n;i++) dis[i]=INF; dis[n]=0;//dis[n]=0;S[n]>=S[0],S[0]-S[n]<=0,dis[n]=0; for(int i=1; i<=n; i++)/*假设第k条边的起点是u,终点是v,以下循环考虑第k条边是否会使得源点v0到v的 最短距离缩短,即判断dist[edges[k].u] + edges[k].w < dist[edges[k].v] 是否成立*/ { for(int k=0; k<edgnum; k++) { u=edg[k].u,v=edg[k].v,w=edg[k].w; if(dis[u]!=INF&&dis[u]+w<dis[v]) { dis[v]=dis[u]+w; } } } for(int k=0; k<edgnum; k++)/*以下是检查,若还有更新则说明存在无限循环的负值回路*/ { u=edg[k].u,v=edg[k].v,w=edg[k].w; if(dis[u]!=INF&&dis[u]+w<dis[v]) { return false; } } return true; } int main() { int u,ii,jj,c; while(scanf("%d%d",&n,&m)!=EOF) { edgnum=0; dis[0]=0; d[0]=0;//d表示前n个点个容量和 for(int i=1;i<=n;i++) { scanf("%d",&c); add(i-1,i,c); add(i,i-1,0); d[i]=d[i-1]+c;//前i个点的容量 } for(int i=0;i<m;i++) { scanf("%d%d%d",&ii,&jj,&c);//i,j add(jj,ii-1,-c); add(ii-1,jj,d[jj]-d[ii-1]); } if(bellman_ford()) printf("%d\n",dis[n]-dis[0]); else printf("Bad Estimations\n"); } return 0; }