zoj 2770 Burn the Linked Camp (差分约束系统)

时间:2023-03-09 15:20:09
zoj 2770 Burn the Linked Camp (差分约束系统)
// 差分约束系统
// 火烧连营
// n个点 m条边 每天边约束i到j这些军营的人数 n个兵营都有容量
// Si表示前i个军营的总数 那么 1.Si-S(i-1)<=C[i] 这里 建边(i-1,i) 权值为 C[i]
// 2.S(i-1)-Si<=0 这里 建边(i,i-1) 权值为 0
// 3.S(j)-S(i-1)>=k => S(i-1)-Sj<=-k 这里建边 (j,i-1) 权值为 -k
// 题目求的事 Sn-S0的最小值 Sn-S0>=m 中符合条件的m最大值就是答案
// 等价 S0-Sn<=-m 求点 Sn 到 S0的最小值 就是求最短路径 (这里可能不好理解,需要慢慢体会)
// #include <iostream>
#include <map>
#include <algorithm>
#include <queue>
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <vector>
using namespace std;
#define MOD 1000000007
#define maxn 20010 // 开始我天真了 maxn=10010 和 m 差不错大 WA的好难过 图中边数应该为 m+2n
#define MAX 100000000
struct node{
int to;
int next;
int val;
}E[maxn];
int num;
int V[];
int C[];
int d[],cnt[];
bool f[];
bool sfpa(int s,int t){// s既表示起点 又表示节点个数
queue <int> Q;
int u,v;
int e;
Q.push(s);
d[s]=;
f[s]=true;
while(!Q.empty()){
u=Q.front(); Q.pop();
cnt[u]++;
if(cnt[u]>s) return false;
f[u]=false;
for(e=V[u];e!=-;e=E[e].next){
v=E[e].to;
if(d[u]+E[e].val<d[v]){
d[v]=d[u]+E[e].val;
if(!f[v])
{
f[v]=true;
Q.push(v);
}
}
}
}
return true;
}
int main(){
int i,j,k;
int n,m;
while(scanf("%d %d",&n,&m)!=EOF){
for(i=;i<=n;i++)
{
scanf("%d",&C[i]);
V[i]=-;
d[i]=MAX;
cnt[i]=;
f[i]=false;
}
num=;
i=;
V[i]=-;
d[i]=MAX;
cnt[i]=;
f[i]=false;
while(m--){
scanf("%d %d %d",&i,&j,&k);
E[num].to=i-;
E[num].val=-k;
E[num].next=V[j];
V[j]=num++;
}
for(i=n;i>=;i--){
E[num].to=i;
E[num].val=C[i];
E[num].next=V[i-];
V[i-]=num++;
E[num].to=i-;
E[num].val=;
E[num].next=V[i];
V[i]=num++;
}
if(sfpa(n,))
printf("%d\n",-d[]);
else
printf("Bad Estimations\n"); } }