ZOJ2770 Burn the Linked Camp(差分约束系统)
区间和一定要联系到前缀和。
- 这题,把前缀和看作点,从s0到sn;
- 对于每一个营地i的容量capi,有这么个关系si-si-1<=capi;
- 对于每一个区间的评估i,j,k,有sj-si-1>=k,即si-1-sj<=k;
- 接下来就是连边了,对于v<=u+w由u向v连权w的边,超级源向n+1个点连权0的边。
- 最后跑SPFA,如果出现负环则无解;而有解的话,所求答案就在d[sn]里,不过因为题目的前缀和是非负整数且要求的最少,所以就要让d中所有数都同时加上合适的数得到另一个真正所求的解。
1 #include<cstdio> 2 #include<cstring> 3 #include<queue> 4 #include<algorithm> 5 using namespace std; 6 #define INF (1<<30) 7 #define MAXN 1111 8 #define MAXM 22222 9 10 struct Edge{ 11 int v,cost,next; 12 }edge[MAXM]; 13 int head[MAXN],NE; 14 void addEdge(int u,int v,int cost){ 15 edge[NE].v=v; edge[NE].cost=cost; edge[NE].next=head[u]; 16 head[u]=NE++; 17 } 18 19 int n,m,d[MAXN],cnt[MAXN]; 20 bool vis[MAXN]; 21 bool SPFA(){ 22 for(int i=0; i<=n; ++i){ 23 vis[i]=0; cnt[i]=0; d[i]=INF; 24 } 25 vis[n+1]=1; cnt[n+1]=1; d[n+1]=0; 26 queue<int> que; 27 que.push(n+1); 28 while(!que.empty()){ 29 int u=que.front(); que.pop(); 30 if(cnt[u]>n+1) return 0; 31 for(int i=head[u]; i!=-1; i=edge[i].next){ 32 int v=edge[i].v; 33 if(d[v]>d[u]+edge[i].cost){ 34 d[v]=d[u]+edge[i].cost; 35 if(!vis[v]){ 36 vis[v]=1; 37 ++cnt[v]; 38 que.push(v); 39 } 40 } 41 } 42 vis[u]=0; 43 } 44 return 1; 45 } 46 int main(){ 47 int a,b,c,cap[MAXN]; 48 while(~scanf("%d%d",&n,&m)){ 49 for(int i=1; i<=n; ++i) scanf("%d",cap+i); 50 51 memset(head,-1,sizeof(head)); 52 NE=0; 53 for(int i=1; i<=n; ++i) addEdge(i-1,i,cap[i]); 54 for(int i=0; i<=n; ++i) addEdge(n+1,i,0); 55 while(m--){ 56 scanf("%d%d%d",&a,&b,&c); 57 addEdge(b,a-1,-c); 58 } 59 if(SPFA()){ 60 int tmp=INF; 61 for(int i=0; i<=n; ++i) tmp=min(tmp,d[i]); 62 if(tmp<0) d[n]-=tmp; 63 printf("%d\n",d[n]); 64 }else puts("Bad Estimations"); 65 } 66 return 0; 67 }