zoj 2770 差分约束
1 /* 2 题意:给出N个营地,每个营地最多可容纳Ci人,给出m个三元组i,j,k分别表示当前营地从i到j至少有 3 k个人,问N个营地总共至少有多少人 4 5 题解:差分约束(SPFA) 6 题目中给出的很多条件都是约束的条件,例如最多有Ci个人,最少有k个人,问的问题也同样是最少多 7 少人,当所有给出的都是限制条件,然后自然会写出一些不等式,然后就可以联想到用差分系统来做 8 (马后炮的想法,当时想的时候也是没有考虑用差分系统),然后就是从题目中找出不等式: 9 设x[i] 为第i个营的人数,s[i] = x[1] + x[2] + … + x[i], s[0] = 0 10 Ci 有: 0 <= s[i] – s[i-1] <= Ci 11 i, j, k有: s[j] – s[i-1] >= k 12 还有: s[i] >= 0 (1 <= i <= n) , 即 s[i] – s[0] >= 0 13 因为题目要求的是最小值,因此需要转换为求最长路,不等式要全变成s[i]-s[j] >= t的形式,然后 14 建图求最长路即可(为什么是求最长路而不是最短路,其实可以通过s[i]-s[j] >= t思考,因为要求 15 的是一个最小值,其中的s[i]-s[j]>=t表示至少大于某个给出值,这样在求的时候才会有一个极限, 16 否则以s[i]-[j]<=t的形式去求,则值可以变成负数无限的小,从而无法求出答案,而首先给出一个限 17 定的最小值的形式,这样就能求出最小值,至于求最长还是求最短路就从不等式的形式去判断,这个 18 想法纯属YY,没有科学证明) 19 */ 20 #include <cstdio> 21 #include <cstring> 22 #include <iostream> 23 #include <queue> 24 25 #define clr(a,b) (memset(a,b,sizeof(a))) 26 #define cpy(a,b) (memcpy(a,b,sizeof(b))) 27 using namespace std; 28 29 const int NV = 1005; 30 const int NE = 15005; 31 const int INF = 0x7f7f7f7f; 32 33 int n; 34 int dis[NV],head[NV],insum[NV]; 35 bool in[NV]; 36 int SZ; 37 struct edge { 38 int v,d,next; 39 }E[NE]; 40 41 inline void init(int nn) { 42 n = nn; 43 SZ = 0; 44 clr(head,-1); 45 clr(insum,0); 46 clr(in,false); 47 clr(dis,0x7f); 48 } 49 inline bool relax(int u,int v,int w) { 50 if(dis[v] == INF || dis[u] + w > dis[v]) {//大于,求最长路 51 dis[v] = dis[u] + w; 52 return true; 53 } 54 return false; 55 } 56 inline bool spfa(int start) { 57 int i; 58 queue<int>q; 59 dis[start] = 0; 60 q.push(start); 61 while(!q.empty()) { 62 int u = q.front(); 63 q.pop(); 64 in[u] = false; 65 for(i = head[u];i != -1;i = E[i].next) { 66 int v = E[i].v; 67 if(relax(u,v,E[i].d) && !in[v]) { 68 in[v] = true; 69 insum[v]++; 70 if (insum[v] >= n) 71 return false; 72 q.push(v); 73 } 74 } 75 } 76 return true; 77 } 78 inline void insert(int from,int to,int dis) { 79 E[SZ].v = to; 80 E[SZ].d = dis; 81 E[SZ].next = head[from]; 82 head[from] = SZ ++; 83 } 84 int main(void) 85 { 86 int m; 87 while (~scanf("%d%d",&n,&m)) 88 { 89 init(n); 90 for(int i=1; i<=n; i++) 91 { 92 int c; 93 scanf("%d",&c); 94 insert(i-1,i,0); 95 insert(i,i-1,-c); 96 insert(0,i,0); 97 } 98 while (m--) 99 { 100 int i,j,k; 101 scanf("%d%d%d",&i,&j,&k); 102 insert(i-1,j,k); 103 } 104 if (spfa(0)) 105 printf("%d\n",dis[n]); 106 else 107 printf("Bad Estimations\n"); 108 } 109 return 0; 110 }