POJ1201 && POJ1716 SPFA
差分约束
POJ 1201
题意:给出n个约束条件,每个约束条件为从整数区间 [ ai , bi ]中选出ci个数,问在满足所有约束条件的情况下,选出数的最少个数。
设S[x]表示0~x中总共选出了多少数
所以从给出的约束条件( ai , bi , ci )得到 S[ bi ]-S[ ai-1 ] ≥ ci,同时还隐含条件: 0 ≤ S[ i ] - S[ i - 1 ] ≤ 1
统一符号:
S[ ai - 1 ] - S[ bi ] ≤ -ci
S[ i - 1 ] - S[ i ] ≤ 0
S[ i ] - S[ i - 1 ] ≤ 1
求从区间最左端到区间最右端的最短路
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
using namespace std;
const int maxn = 50000 + 10;
const int INF = 0x3f3f3f3f;
struct edge{int to, next, cost;};
edge e[maxn*4];
int head[maxn];
int dist[maxn];
int m, cnt;
int MIN, MAX;
void add_edge(int x, int y, int w)
{
e[cnt].to = y;
e[cnt].next = head[x];
e[cnt].cost = w;
head[x] = cnt;
cnt++;
}
bool spfa()
{
for(int i = MIN; i <= MAX; i++) dist[i] = 0;
int vis[maxn]; memset(vis, 0, sizeof(vis));
bool inque[maxn]; memset(inque, true, sizeof(inque));
queue<int> q;
for(int i = MIN; i <= MAX; i++) q.push(i);
while(!q.empty()){
int cur = q.front(); q.pop(); inque[cur] = false;
for(int i = head[cur]; ~i; i = e[i].next){
if(dist[e[i].to] > dist[cur] + e[i].cost){
dist[e[i].to] = dist[cur] + e[i].cost;
if(!inque[e[i].to]){
q.push(e[i].to); inque[e[i].to] = true;
if(++vis[e[i].to] > (MAX-MIN)) return false;
}
}
}
}
return true;
}
int main()
{
while(~scanf("%d", &m)){
memset(head, -1, sizeof(head));
MIN = INF, MAX = -INF;
for(int i = 0; i < m; i++){
int x, y, w;
scanf("%d%d%d", &x, &y, &w);
add_edge(y, x-1, -w);
MAX = max(y, MAX);
MIN = min(x-1, MIN);
}
for(int i = MIN+1; i <= MAX; i++){
add_edge(i, i-1, 0);
add_edge(i-1, i, 1);
}
spfa();
printf("%d\n",dist[MAX]-dist[MIN]);
}
return 0;
}
POJ 1716
和上题一样,只是把从区间内取的数改为固定的两个,求取出数的最少数量
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
using namespace std;
const int maxn = 50000 + 10;
const int INF = 0x3f3f3f3f;
struct edge{int to, next, cost;};
edge e[maxn*4];
int head[maxn];
int dist[maxn];
int m, cnt;
int MIN, MAX;
void add_edge(int x, int y, int w)
{
e[cnt].to = y;
e[cnt].next = head[x];
e[cnt].cost = w;
head[x] = cnt;
cnt++;
}
bool spfa()
{
for(int i = MIN; i <= MAX; i++) dist[i] = 0;
int vis[maxn]; memset(vis, 0, sizeof(vis));
bool inque[maxn]; memset(inque, true, sizeof(inque));
queue<int> q;
for(int i = MIN; i <= MAX; i++) q.push(i);
while(!q.empty()){
int cur = q.front(); q.pop(); inque[cur] = false;
for(int i = head[cur]; ~i; i = e[i].next){
if(dist[e[i].to] > dist[cur] + e[i].cost){
dist[e[i].to] = dist[cur] + e[i].cost;
if(!inque[e[i].to]){
q.push(e[i].to); inque[e[i].to] = true;
if(++vis[e[i].to] > (MAX-MIN)) return false;
}
}
}
}
return true;
}
int main()
{
while(~scanf("%d", &m)){
memset(head, -1, sizeof(head));
MIN = INF, MAX = -INF;
for(int i = 0; i < m; i++){
int x, y;
scanf("%d%d", &x, &y);
x++, y++;
add_edge(y, x-1, -2);
MAX = max(y, MAX);
MIN = min(x-1, MIN);
}
for(int i = MIN+1; i <= MAX; i++){
add_edge(i, i-1, 0);
add_edge(i-1, i, 1);
}
spfa();
printf("%d\n",dist[MAX]-dist[MIN]);
}
return 0;
}