题目链接
POJ1201 http://poj.org/problem?id=1201
题解
差分约束
令 \(a[i]\) 表示是否选择 \(i\),\(s[i]\) 表示 \(a[i]\) 的前缀和
对 \(s[i] \quad i \in [-1,50000]\) 分别建立一个点
首先有
- \[s[i] - s[i - 1] \ge 0\]
- \[s[i] - s[i - 1] \le 1\]
然后就是限制条件
\[s[b] - s[a - 1] \ge c\]
然后就没了
用 \(spfa\) 跑最长路
由于题目保证有解, 所以不会存在正环
复杂度上界是 \(O(nm)\) 的, 但由于保证有解, 而且 \(spfa\) 的玄学复杂度, 并不会 \(T\)
- #include<algorithm>
- #include<iostream>
- #include<cstring>
- #include<cstdio>
- #include<queue>
- #include<cmath>
- #include<map>
- #define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
- #define REP(i,n) for (int i = 1; i <= (n); i++)
- #define mp(a,b) make_pair<int,int>(a,b)
- #define cls(s) memset(s,-0x3f3f3f3f,sizeof(s))
- #define cp pair<int,int>
- #define LL long long int
- using namespace std;
- const int maxn = 50005,maxm = 200005,INF = 1000000000;
- inline int read(){
- int out = 0,flag = 1; char c = getchar();
- while (c <48 || c> 57){if (c == '-') flag = -1; c = getchar();}
- while (c>= 48 && c <= 57){out = (out <<3) + (out << 1) + c - 48; c = getchar();}
- return out * flag;
- }
- int h[maxn],ne,N = 50001;
- struct EDGE{int to,nxt,w;}ed[maxm];
- inline void build(int u,int v,int w){
- ed[++ne] = (EDGE){v,h[u],w}; h[u] = ne;
- }
- queue<int> q;
- int d[maxn],vis[maxn];
- void spfa(){
- for (int i = 0; i <= N; i++) d[i] = -INF; d[N] = 0;
- q.push(N);
- int u;
- while (!q.empty()){
- u = q.front(); q.pop();
- vis[u] = false;
- Redge(u) if (d[to = ed[k].to] < d[u] + ed[k].w){
- d[to] = d[u] + ed[k].w;
- if (!vis[to]) q.push(to),vis[to] = true;
- }
- }
- }
- int main(){
- int m = read(),a,b,c;
- while (m--){
- a = read(); b = read(); c = read();
- a--; if (a == -1) a = N;
- build(a,b,c);
- }
- build(N,0,0); build(0,N,-1);
- for (int i = 1; i < N; i++)
- build(i - 1,i,0),build(i,i - 1,-1);
- spfa();
- /*for (int i = 0; i < 15; i++)
- printf("d[%d] = %d\n",i,d[i]);*/
- printf("%d\n",d[N - 1]);
- return 0;
- }
来源: http://www.bubuko.com/infodetail-2637735.html