题目很好理解,但是不懂得差分约束系统的人做起来比较困难。差分约束系统是图论问题中数形结合的一个很好的例子,它通过列出不等式,利用不等式间的关系构图,将原问题转化成常见的求单源最长路径或最短路径问题。一般地,给出一段线性区间(或者问题可以装化成线性区间问题),求该区间内可存在的最大数量(最小数量)的元素个数,就可考虑用差分约束模型(这是个人见解,我还没系统地做出总结)。
对于本题,设d[i]为第0个兵营到第i个兵营至少的士兵个数,则有方程:
0=<d[i]-d[i-1]<=ci,ci为第i个兵营至少的士兵数。而从兵营i到j的士兵个数,则有方程:w=<d[j]-d[i-1]<=sum[i...j],其中sum[i...j]为从兵营i到j的至少士兵总数。用spfa算法解答。
以下是代码:
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int M=12000;
const int N=1200;
const int inf=1<<29;
struct node
{
int v,w;
int next;
}edge[4*M];
int head[N],num;
int dis[N],d[N],tim[N];
bool vis[N];
int n,m;
void init()
{
int i;
for(i=0;i<=n+2;i++)
head[i]=-1;
num=0;
}
void addege(int u,int v,int w)
{
edge[num].v=v;
edge[num].w=w;
edge[num].next=head[u];
head[u]=num++;
}
bool spfa()
{
int s=0;
int queue[100*N+1],front=0,rear=0;
int i,j;
for(i=0;i<=n+1;i++)
{
vis[i]=0;
dis[i]=-inf;
tim[i]=0;
}
dis[s]=0;
queue[rear++]=s;
vis[s]=true;
tim[s]++;
while(front<rear)
{
i=queue[front++];
vis[i]=false;
for(j=head[i];j!=-1;j=edge[j].next)
{
int v=edge[j].v;
if(dis[v]<dis[i]+edge[j].w)
{
dis[v]=dis[i]+edge[j].w;
if(!vis[v])
{
vis[v]=1;
queue[rear++]=v;
tim[v]++;
}
}
if(tim[v]>=n-1) return false;
}
}
return true;
}
int main()
{
while(scanf("%d%d",&n,&m)==2)
{
init();
int i,j;
int a,b,c;
for(i=1;i<=n;i++)
{
scanf("%d",&d[i]);
addege(i,i-1,-d[i]);
addege(i-1,i,0);
}
for(i=0;i<m;i++)
{
scanf("%d%d%d",&a,&b,&c);
int sum=0;
for(j=a;j<=b;j++)
sum+=d[j];
addege(a-1,b,c);
addege(b,a-1,-sum);
}
if(spfa())
printf("%d/n",dis[n]);
else
printf("Bad Estimations/n");
}
return 0;
}