原题:ZOJ 3668 http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3668
典型差分约束题。
将sum[0] ~ sum[n] 作为节点,A<=sum[R]-sum[L-1]<=B可以分别建边:
x(L-1)-->xR w = B
xR --> x(L-1) w = -A
注意还有 -10000<=sum[i]-sum[i-1]<=10000 (for i in (2,n)),所以相邻点之间还要建边,(WA了很多次)这样的话就不用另加节点来使联通了,因为必会连通。如果出现负环,则无解。
用SPFA求最短路并判负环,求出的节点的dis[i]如果为INF,则任意取值(事实上此题不会),否则dis[i]就是sum[i],然后根据sum数组两两之间差值来求出a[i]。
代码:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <vector> #include <map> #include <queue> #define Mod 1000000007 using namespace std; #define N 10017 vector<pair<int,int> > G[N]; int dis[N],inq[N],cnt[N]; int sum[N]; int n,m; queue<int> que; bool SPFA(int s) { int u,v,i,w; for(i=0;i<=n;i++) { inq[i] = 0; dis[i] = Mod; cnt[i] = 0; } while(!que.empty()) que.pop(); que.push(s); dis[s] = 0; cnt[s] = 1; inq[s] = 1; //for(i=0;i<=n;i++) //que.push(i); while(!que.empty()) { u = que.front(); que.pop(); inq[u] = 0; for(i=0;i<G[u].size();i++) { v = G[u][i].first; w = G[u][i].second; if(dis[v] > dis[u] + w) { dis[v] = dis[u] + w; if(!inq[v]) { inq[v] = 1; cnt[v]++; if(cnt[v] >= n+1) return false; que.push(v); } } } } return true; } int main() { int i,j; int L,R,A,B; while(scanf("%d%d",&n,&m)!=EOF) { for(i=0;i<=n+3;i++) G[i].clear(); while(m--) { scanf("%d%d%d%d",&L,&R,&A,&B); G[R].push_back(make_pair(L-1,-A)); G[L-1].push_back(make_pair(R,B)); } for(i=1;i<=n;i++) { G[i].push_back(make_pair(i-1,10000)); G[i-1].push_back(make_pair(i,10000)); } if(SPFA(0)) { for(i=1;i<=n+1;i++) { if(dis[i] != Mod) sum[i] = dis[i]; else sum[i] = sum[i-1]; } printf("%d",sum[1]); for(i=2;i<=n;i++) printf(" %d",sum[i]-sum[i-1]); printf("\n"); } else puts("The spacecraft is broken!"); } return 0; }