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;
}
posted @ 2017-07-05 20:57  />.<\  阅读(69)  评论(0编辑  收藏  举报