差分约束系统
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;
}