【网络流】网络流复习

1、最大流

poj1149 PIGS


/****************************\
 * @prob: poj1149 PIGS      *
 * @auth: Wang Junji        *
 * @stat: Accepted.         *
 * @date: June. 12th, 2012  *
 * @memo: 最大流             *
\****************************/
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <string>

const int maxN = 1010, maxM = 10010, INF = 0x3f3f3f3f;

struct Edge
{
    int v, f; Edge *next, *op; Edge() {}
    Edge(int v, int f, Edge* next): v(v), f(f), next(next) {}
} *edge[maxN], __edge[maxM], *tot = __edge;
int cap[maxN], open[maxN], n, m, S, T, N;

inline void Ins(int u, int v, int f)
{
    edge[u] = new (tot++) Edge(v, f, edge[u]);
    edge[v] = new (tot++) Edge(u, 0, edge[v]);
    edge[u] -> op = edge[v];
    edge[v] -> op = edge[u];
    return;
}

inline void gmin(int& a, const int& b) {if (b < a) a = b; return;}

inline int Sap()
{
    static Edge *cur[maxN], *p; memcpy(cur, edge, sizeof edge);
    static int pre[maxN], d[maxN], cnt[maxN];
    int ans = 0; pre[S] = S, cnt[0] = N;
    for (int u = S; d[S] < N;)
    {
        if (u == T)
        {
            int max_flow = INF;
            for (int i = S; i - T; i = cur[i] -> v)
                gmin(max_flow, cur[i] -> f);
            for (int i = S; i - T; i = cur[i] -> v)
                cur[i] -> f -= max_flow, cur[i] -> op -> f += max_flow;
            ans += max_flow, u = S;
        }
        for (p = cur[u]; p; p = p -> next)
        if (p -> f > 0 && d[u] == d[p -> v] + 1)
        {
            cur[u] = p, pre[p -> v] = u, u = p -> v;
            break; //
        }
        if (!p)
        {
            if (!--cnt[d[u]]) break;
            cur[u] = edge[u]; int Min = N;
            for (Edge* p = edge[u]; p; p = p -> next)
                if (p -> f > 0) gmin(Min, d[p -> v]);
            ++cnt[d[u] = Min + 1], u = pre[u];
        }
    }
    return ans;
}

int main()
{
    freopen("pigs.in", "r", stdin);
    freopen("pigs.out", "w", stdout);
    scanf("%d%d", &m, &n);
    S = n + 1, T = n + 2, N = n + 2;
    for (int i = 1; i < m + 1; ++i) scanf("%d", cap + i);
    for (int i = 1, K, tmp, flow; i < n + 1; ++i)
    {
        scanf("%d", &K);
        while (K--) 
            scanf("%d", &tmp),
            Ins(open[tmp] ? open[tmp] : S, i, open[tmp] ? INF : cap[tmp]),
            open[tmp] = i;
        scanf("%d", &flow);
        Ins(i, T, flow);
    }
    printf("%d\n", Sap());
    return 0;
}

/*

建模方法:
从源点向第一个打开每个猪圈的人连一条容量为猪圈初始数目的边;
从每个人向下一个打开他当前打开的某个猪圈的人连一条容量为正无穷的边;(若A打开了1、2号猪圈,B是A的下一个且打开了1、3号猪圈,则A向B连边。)
从每个人向汇点连一条容量为他的购买量的边。
求最大流。

*/


poj1637 Sightseeing tour


/************************************\
 * @prob: poj1637 Sightseeing tour  *
 * @auth: Wang Junji                *
 * @stat: Accepted.                 *
 * @date: June. 12th, 2012          *
 * @memo: 最大流                     *
\************************************/
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <string>

const int maxN = 210, maxM = 4010, INF = 0x3f3f3f3f;

struct Edge
{
    int v, f; Edge *next, *op; Edge() {}
    Edge(int v, int f, Edge* next): v(v), f(f), next(next) {}
} *edge[maxN], __edge[maxM], *tot;
int In[maxN], Out[maxN], n, m, N, S, T, t;

inline void Ins(int u, int v, int f)
{
    edge[u] = new (tot++) Edge(v, f, edge[u]);
    edge[v] = new (tot++) Edge(u, 0, edge[v]);
    edge[u] -> op = edge[v];
    edge[v] -> op = edge[u];
    return;
}

inline void gmin(int& a, const int& b) {if (b < a) a = b; return;}

inline int Sap()
{
    static Edge *cur[maxN], *p;
    static int pre[maxN], d[maxN], cnt[maxN];
    memset(d, 0, sizeof d);
    memset(cnt, 0, sizeof cnt);
    memcpy(cur, edge, sizeof edge);
    cnt[0] = N; pre[S] = S; int ans = 0;
    for (int u = S; d[S] < N;)
    {
        if (u == T)
        {
            int max_flow = INF;
            for (int i = S; i - T; i = cur[i] -> v)
                gmin(max_flow, cur[i] -> f);
            for (int i = S; i - T; i = cur[i] -> v)
                cur[i] -> f -= max_flow, cur[i] -> op -> f += max_flow;
            ans += max_flow, u = S;
        }
        for (p = cur[u]; p; p = p -> next)
        if (p -> f > 0 && d[u] == d[p -> v] + 1)
        {
            cur[u] = p, pre[p -> v] = u, u = p -> v;
            break;
        }
        if (!p)
        {
            if (!--cnt[d[u]]) break;
            cur[u] = edge[u]; int Min = N;
            for (Edge* p = edge[u]; p; p = p -> next)
                if (p -> f > 0) gmin(Min, d[p -> v]);
            ++cnt[d[u] = Min + 1], u = pre[u];
        }
    }
    return ans;
}

int main()
{
    freopen("tour.in", "r", stdin);
    freopen("tour.out", "w", stdout);
    scanf("%d", &t);
    while (t--)
    {
        scanf("%d%d", &n, &m);
        memset(Out, 0, sizeof Out);
        memset(In, 0, sizeof In);
        memset(edge, 0, sizeof edge);
        tot = __edge;
        S = n + 1, T = n + 2, N = n + 2;
        for (int i = 0, u, v, sgn; i < m; ++i)
        {
            scanf("%d%d%d", &u, &v, &sgn), ++Out[u], ++In[v];
            if (!sgn && u - v) Ins(u, v, 1);
        }
        bool flag = 1; int req = 0;
        for (int i = 1, tmp; i < n + 1; ++i)
        {
            if ((tmp = std::abs(Out[i] - In[i])) & 1) {flag = 0; break;}
            req += tmp >>= 1;
            if (Out[i] > In[i]) Ins(S, i, tmp);
            if (In[i] > Out[i]) Ins(i, T, tmp);
        }
        if (!flag) {printf("impossible\n"); continue;}
        if (!req || Sap() == (req >> 1)) printf("possible\n");
        else printf("impossible\n");
    }
    return 0;
}

/*

混合图欧拉回路。
建模方法:
先将无向图随便定向,统计每个点的出入度之差,若发现存在奇点(出入度之差为奇数),那么一定不存在欧拉回路,否则,进行下一步;
去掉有向边,不改变之前随便定向的无向边,将其容量设为1;
添加源点和汇点,从源点向入度大于出度的点连一条边,容量为出入度之差的一半,从出度大于入度的点向汇点连一条边,容量为出入度之差的一半。
若存在满流,则有解。将所有容量为1的边反向,再加上原来的有向边,则得到一种欧拉回路的方案。
若不存在满流,则无解。

*/


poj2391 Ombrophobic Bovines


/*****************************************\
 * @prob: poj2391 Ombrophobic Bovines    *
 * @auth: Wang Junji                     *
 * @stat: Accepted.                      *
 * @date: June. 13th, 2012               *
 * @memo: 最大流,二分检验、Floyd预处理     *
\*****************************************/
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <string>

typedef long long int64;
const int maxN = 410, maxM = 12010, INF = 0x3f3f3f3f;
const int64 INFLL = 0x3f3f3f3f3f3f3f3fLL;
struct Edge
{
    int v, f; Edge *next, *op; Edge() {}
    Edge(int v, int f, Edge* next): v(v), f(f), next(next) {}
} *edge[maxN], __edge[maxM], *tot;
int from[maxN], to[maxN], n, m, S, T, N, Need;
int64 mp[maxN][maxN];

template <typename _Tp> inline _Tp& gmin(_Tp& a, const _Tp& b) {return a < b ? a : (a = b);}
template <typename _Tp> inline _Tp& gmax(_Tp& a, const _Tp& b) {return a > b ? a : (a = b);}

inline void Ins(int u, int v, int f)
{
    if (!f) return;
    edge[u] = new (tot++) Edge(v, f, edge[u]);
    edge[v] = new (tot++) Edge(u, 0, edge[v]);
    edge[u] -> op = edge[v];
    edge[v] -> op = edge[u];
    return;
}

inline int Sap()
{
    static Edge *cur[maxN], *p;
    static int pre[maxN], d[maxN], cnt[maxN];
    memset(d, 0, sizeof d);
    memset(cnt, 0, sizeof cnt);
    memcpy(cur, edge, sizeof edge);
    cnt[0] = N; pre[S] = S; int ans = 0;
    for (int u = S; d[S] < N;)
    {
        if (u == T)
        {
            int max_flow = INF;
            for (int i = S; i - T; i = cur[i] -> v)
                gmin(max_flow, cur[i] -> f);
            for (int i = S; i - T; i = cur[i] -> v)
                cur[i] -> f -= max_flow, cur[i] -> op -> f += max_flow;
            ans += max_flow, u = S;
        }
        for (p = cur[u]; p; p = p -> next)
        if (p -> f > 0 && d[u] == d[p -> v] + 1)
        {
            cur[u] = p, pre[p -> v] = u, u = p -> v;
            break;
        }
        if (!p)
        {
            if (!--cnt[d[u]]) break;
            cur[u] = edge[u]; int Min = N;
            for (Edge* p = edge[u]; p; p = p -> next)
                if (p -> f > 0) gmin(Min, d[p -> v]);
            ++cnt[d[u] = Min + 1], u = pre[u];
        }
    }
    return ans;
}

inline bool check(const int64& Lim)
{
    memset(edge, 0, sizeof edge); tot = __edge;
    for (int i = 1; i < n + 1; ++i)
        Ins(S, i, from[i]), Ins(i + n, T, to[i]);
    for (int i = 1; i < n + 1; ++i)
    for (int j = 1; j < n + 1; ++j)
        if (mp[i][j] <= Lim) Ins(i, j + n, INF);
    return Sap() == Need;
}

int main()
{
    freopen("Bovines.in", "r", stdin);
    freopen("Bovines.out", "w", stdout);
    scanf("%d%d", &n, &m);
    S = (n << 1) + 1, N = T = (n << 1) + 2;
    for (int i = 1; i < n + 1; ++i)
        scanf("%d%d", from + i, to + i), Need += from[i];
    for (int i = 1; i < n + 1; ++i)
    for (int j = 1; j < n + 1; ++j)
        if (i - j) mp[i][j] = INFLL;
    for (int i = 0, u, v; i < m; ++i)
    {
        int64 d; scanf("%d%d%lld", &u, &v, &d);
        mp[v][u] = gmin(mp[u][v], d);
    }
    for (int k = 1; k < n + 1; ++k)
    for (int i = 1; i < n + 1; ++i) if (k - i)
    for (int j = 1; j < n + 1; ++j) if (j - i && j - k)
        gmin(mp[i][j], mp[i][k] + mp[k][j]);
    int64 Max = 0;
    for (int i = 1; i < n + 1; ++i)
    for (int j = 1; j < n + 1; ++j)
        if (mp[i][j] < INFLL) gmax(Max, mp[i][j]);
    int64 L = 0, R = Max + 1;
    while (L < R)
    {
        int64 Mid = (L + R) >> 1;
        if (check(Mid)) R = Mid;
        else L = Mid + 1;
    }
    printf("%lld\n", R <= Max ? R : -1);
    return 0;
}

/*

建模方法:
先Floyd预处理出每两个点的距离。
二分时间限制,把每个点i拆成i和i`,从源点到每个点i连一条容量为该点初始奶牛数目的边,从每个点i`连一条容量为该点庇护所的容量。
若任意点对(i, j)的距离不超过时间限制,则从i向j`连一条容量为正无穷的边。
求最大流,若最大流等于奶牛数之和,那么合法,否则不合法。
注意边表要开大,用long long类型。

*/


poj2699 The Maximum Number of Strong Kings


/******************************************************\
 * @prob: poj2699 The Maximum Number of Strong Kings  *
 * @auth: Wang Junji       * @stat: Accepted.         *
 * @date: June. 13th, 2012 * @memo: 最大流,枚举答案    *
\******************************************************/
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <string>

const int maxN = 510, maxM = 30010, INF = 0x3f3f3f3f;
struct Edge
{
    int v, f; Edge *next, *op; Edge() {}
    Edge(int v, int f, Edge* next): v(v), f(f), next(next) {}
} *edge[maxN], __edge[maxM], *__tot;
int score[maxN], more[maxN], n, t, S, T, N, tot;

inline void Ins(int u, int v, int f)
{
    if (!f) return;
    edge[u] = new Edge(v, f, edge[u]);
    edge[v] = new Edge(u, 0, edge[v]);
    edge[u] -> op = edge[v];
    edge[v] -> op = edge[u];
    return;
}

inline int& gmin(int& a, const int& b) {return a < b ? a : (a = b);}
inline int& gmax(int& a, const int& b) {return a > b ? a : (a = b);}

inline int Sap()
{
    static Edge *cur[maxN], *p;
    static int pre[maxN], d[maxN], cnt[maxN];
    memset(d, 0, sizeof d);
    memset(cnt, 0, sizeof cnt);
    cnt[0] = N; pre[S] = S; int ans = 0;
    for (int u = S; d[S] < N;)
    {
        if (u == T)
        {
            int max_flow = INF;
            for (int i = S; i - T; i = cur[i] -> v)
                gmin(max_flow, cur[i] -> f);
            for (int i = S; i - T; i = cur[i] -> v)
                cur[i] -> f -= max_flow, cur[i] -> op -> f += max_flow;
            ans += max_flow, u = S;
        }
        for (p = cur[u]; p; p = p -> next)
        if (p -> f > 0 && d[u] == d[p -> v] + 1)
        {
            cur[u] = p, pre[p -> v] = u, u = p -> v;
            break;
        }
        if (!p)
        {
            if (!--cnt[d[u]]) break;
            cur[u] = edge[u]; int Min = N;
            for (Edge* p = edge[u]; p; p = p -> next)
                if (p -> f > 0) gmin(Min, d[p -> v]);
            ++cnt[d[u] = Min + 1], u = pre[u];
        }
    }
    return ans;
}

int main()
{
    freopen("king.in", "r", stdin);
    freopen("king.out", "w", stdout);
    scanf("%d\n", &t);
    while (t--)
    {
        static char str[100]; char* __str = str;
        fgets(__str, 100, stdin); int tmp = 0; n = 0;
        while (sscanf(__str, "%d%n", score + ++n, &tmp) != EOF)
            __str += tmp;
        --n;
        int ans = 1;
        for (int i = 1; i < n + 1; ++i)
        {
            more[i] = 0;
            for (int j = i + 1; j < n + 1; ++j)
                if (score[j] > score[i]) ++more[i];
        }
        int pos = n - 1;
        for (; pos && score[pos] == score[pos + 1]; --pos) ++ans;
        tot = n * (n - 1) >> 1;
        S = (n << 1) + tot + 1, T = N = (n << 1) + tot + 2;
        for (; pos && ++ans; --pos)
        {
            if (score[pos] < more[pos]) {--ans; break;}
            memset(edge, 0, sizeof edge); __tot = __edge;
            int ths = n << 1;
            for (int i = 1; i < n + 1; ++i)
            {
                Ins(i + n, T, score[i]);
                if (i >= pos) Ins(i, i + n, score[i] - more[i]);
                else Ins(i, i + n, score[i]);
            }
            for (int i = 1; i < n; ++i)
            for (int j = i + 1; j < n + 1; ++j)
            {
                Ins(S, ++ths, 1);
                if (i >= pos && score[i] < score[j]) Ins(ths, i + n, 1);
                else Ins(ths, i, 1), Ins(ths, j, 1);
            }
            if (Sap() < tot) {--ans; break;}
        }
        printf("%d\n", ans);
    }
    return 0;
}

/*

建模方法:
枚举Strong King的个数C,则得分最高的C个选手一定是Strong King;
将每场比赛k作为一个结点,并且将每个选手i拆成i和i`两个结点;
从源点到每场比赛连一条容量为1的边;
从每个选手i到汇点连一条容量为score[i]的边;
对于每个选手i,若i是Strong King,则从i`到i连一条容量为score[i] - more[i]的边(其中more[i]为比i分数高的选手的个数),否则从i`到i连一条容量为score[i]的边;
对于每场比赛k的两个选手i, j(score[i]<=score[j]),若i是Strong King,那么从k到i连一条容量为1的边,否则从k到i`和j`分别连一条容量为1的边。

对此建模方法的解释:
连到每个选手i的边表示该场比赛i必须赢;
从i`连到i的边表示剩下的i可以赢的场数;
连到i`的边表示该场比赛可赢可不赢。

*/


poj3281 Dining


/****************************\
 * @prob: poj3281 Dining    *
 * @auth: Wang Junji        *
 * @stat: Accepted.         *
 * @date: June. 14th, 2012  *
 * @memo: 最大流             *
\****************************/
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <string>

const int maxN = 410, maxM = 40010, INF = 0x3f3f3f3f;

struct Edge
{
    int v, f; Edge *next, *op; Edge() {}
    Edge(int v, int f, Edge* next): v(v), f(f), next(next) {}
} *edge[maxN], __edge[maxM], *tot = __edge;
int n, F, D, S, T, N;

inline void Ins(int u, int v, int f)
{
    if (!f) return;
    edge[u] = new (tot++) Edge(v, f, edge[u]);
    edge[v] = new (tot++) Edge(u, 0, edge[v]);
    edge[u] -> op = edge[v];
    edge[v] -> op = edge[u];
    return;
}

inline int& gmin(int& a, const int& b) {return a < b ? a : (a = b);}

inline int Sap()
{
    static Edge *cur[maxN], *p;
    static int pre[maxN], d[maxN], cnt[maxN];
    memcpy(cur, edge, sizeof cur);
    cnt[0] = N, pre[S] = S; int ans = 0;
    for (int u = S; d[S] < N;)
    {
        if (u == T)
        {
            int max_flow = INF;
            for (int i = S; i - T; i = cur[i] -> v)
                gmin(max_flow, cur[i] -> f);
            for (int i = S; i - T; i = cur[i] -> v)
                cur[i] -> f -= max_flow, cur[i] -> op -> f += max_flow;
            ans += max_flow, u = S;
        }
        for (p = cur[u]; p; p = p -> next)
        if (p -> f > 0 && d[u] == d[p -> v] + 1)
        {
            cur[u] = p, pre[p -> v] = u, u = p -> v;
            break;
        }
        if (!p)
        {
            if (!--cnt[d[u]]) break;
            cur[u] = edge[u]; int Min = N;
            for (Edge* p = edge[u]; p; p = p -> next)
                if (p -> f > 0) gmin(Min, d[p -> v]);
            ++cnt[d[u] = Min + 1], u = pre[u];
        }
    }
    return ans;
}

int main()
{
    freopen("Dining.in", "r", stdin);
    freopen("Dining.out", "w", stdout);
    scanf("%d%d%d", &n, &F, &D);
    S = (n << 1) + F + D + 1, N = T = (n << 1) + F + D + 2;
    for (int i = 1, Fi, Di, _F, _D; i < n + 1; ++i)
    {
        scanf("%d%d", &_F, &_D); Ins(i + F, i + F + n, 1);
        while (_F--) scanf("%d", &Fi), Ins(Fi, i + F, 1);
        while (_D--) scanf("%d", &Di), Ins(i + F + n, Di + F + (n << 1), 1);
    }
    for (int i = 1; i < F + 1; ++i) Ins(S, i, 1);
    for (int i = 1; i < D + 1; ++i) Ins(i + F + (n << 1), T, 1);
    printf("%d\n", Sap());
    return 0;
}

/*

建模方法:
将每头牛i拆成两个点i和i`。
从i到i`连一条容量为1的边;
从i喜欢的食物向i连一条边(容量无所谓);
从i`向i喜欢的饮料连一条边(容量无所谓);
从源点向每个食物连一条容量为1的边,从每个饮料向汇点连一条容量为1的边。

*/

2、最小割

poj1815 Friendship 


/******************************\
 * @prob: poj1815 Friendship  *
 * @auth: Wang Junji          *
 * @stat: Accepted.           *
 * @date: June 14th, 2012     *
 * @memo: 最小割               *
\******************************/
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <string>

const int maxN = 410, maxM = 160010, INF = 0x3f3f3f3f;

struct Edge
{
    int v, f, c; Edge *next, *op; Edge() {}
    Edge(int v, int f, Edge* next): v(v), f(f), c(f), next(next) {}
} *edge[maxN], __edge[maxM], *tot = __edge; bool marked[maxN];
int res[maxN], N, n, S, T;

inline void Ins(int u, int v, int f)
{
    if (!f) return;
    edge[u] = new (tot++) Edge(v, f, edge[u]);
    edge[v] = new (tot++) Edge(u, 0, edge[v]);
    edge[u] -> op = edge[v];
    edge[v] -> op = edge[u];
    return;
}

inline void rm(int u)
{
    for (Edge* p = edge[u]; p; p = p -> next)
        if (p -> v == u + n) {p -> f = p -> op -> f = 0; break;}
    return;
}

inline void reIns(int u)
{
    for (Edge* p = edge[u]; p; p = p -> next)
    if (p -> v == u + n)
    {
        p -> f = p -> c, p -> op -> f = p -> op -> c;
        break;
    }
    return;
}

inline void recover()
{
    for (int u = 1; u < (n << 1) + 1; ++u) if (!marked[u])
    for (Edge* p = edge[u]; p; p = p -> next) if (!marked[p -> v])
        p -> f = p -> c;
    return;
}

inline int& gmin(int& a, const int& b) {return a < b ? a : (a = b);}

int Sap()
{
    static Edge *cur[maxN], *p;
    static int pre[maxN], d[maxN], cnt[maxN];
    memset(d, 0, sizeof d);
    memset(cnt, 0, sizeof cnt);
    memcpy(cur, edge, sizeof edge);
    pre[S] = S; cnt[0] = N; int ans = 0;
    for (int u = S; d[S] < N;)
    {
        if (u == T)
        {
            int max_flow = INF;
            for (int i = S; i - T; i = cur[i] -> v)
                gmin(max_flow, cur[i] -> f);
            for (int i = S; i - T; i = cur[i] -> v)
                cur[i] -> f -= max_flow, cur[i] -> op -> f += max_flow;
            ans += max_flow, u = S;
        }
        for (p = cur[u]; p; p = p -> next)
        if (p -> f > 0 && d[u] == d[p -> v] + 1)
        {
            cur[u] = p, pre[p -> v] = u, u = p -> v;
            break;
        }
        if (!p)
        {
            if (!--cnt[d[u]]) break;
            cur[u] = edge[u]; int Min = N;
            for (Edge* p = edge[u]; p; p = p -> next)
                if (p -> f > 0) gmin(Min, d[p -> v]);
            ++cnt[d[u] = Min + 1], u = pre[u];
        }
    }
    return ans;
}

int main()
{
    freopen("Friendship.in", "r", stdin);
    freopen("Friendship.out", "w", stdout);
    scanf("%d%d%d", &n, &S, &T); int f; T += n, N = n << 1;
    for (int i = 1; i < n + 1; ++i)
    for (int j = 1; j < n + 1; ++j)
        scanf("%d", &f), (f && i - j) ? Ins(i + n, j, INF) : (void)0;
    for (int i = 1; i < n + 1; ++i) Ins(i, i + n, i == S || i == T - n ? INF : 1);
    int flow = Sap(), cnt = 0;
    for (int i = 1, cur; i < n + 1 && flow > 0; ++i)
    if (i - S && i != T - n)
    {
        recover(); rm(i);
        if ((cur = Sap()) < flow)
            flow = cur, marked[res[cnt++] = i] = marked[i + n] = 1;
    }
    if (flow > 0) printf("NO ANSWER!\n");
    else
    {
        printf("%d\n", cnt);
        for (int i = 0; i < cnt; ++i) printf("%d ", res[i]);
        printf("\n");
    }
    return 0;
}

/*

建模方法:
把每个点i拆成i和i`两点,从每个i到i`连一条容量为1的边(S到S`、T到T`容量为正无穷);
若i到j有边,则从i`到j连一条容量为正无穷的边。

然后求最小割,从小到大枚举每一个点是否在最小割中(若去掉该点后最小割变小,那么说明该店在最小割中,记录该点为一个解;否则将该点放回图中),这样就能保证字典序。

*/

3、有上下界


4、费用流

poj2680 Intervals


/**********************************\
 * @prob: poj3680 Intervals       *
 * @auth: Wang Junji              *
 * @stat: Accepted.               *
 * @date: June. 15th, 2012        *
 * @memo: 最大费用流、区间离散化     *
\**********************************/
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <string>

const int maxN = 510, maxM = 2010, INF = 0x3f3f3f3f;

struct Edge
{
    int u, v, f, d; Edge *next, *op; Edge() {}
    Edge(int u, int v, int f, int d, Edge* next):
        u(u), v(v), f(f), d(d), next(next) {}
} *edge[maxN], __edge[maxM], *tot = __edge;
int L[maxN], R[maxN], w[maxN], tab[maxN], n, K, cnt, S, T, t;

inline void Ins(int u, int v, int f, int d)
{
    edge[u] = new (tot++) Edge(u, v, f, d, edge[u]);
    edge[v] = new (tot++) Edge(v, u, 0, -d, edge[v]);
    edge[u] -> op = edge[v];
    edge[v] -> op = edge[u];
    return;
}

int Spfa()
{
    static const int SIZE = 0xffff;
    static bool marked[maxN]; static Edge* pre[maxN];
    static int q[SIZE + 1], max_flow[maxN], dist[maxN];
    memset(dist, ~0x3f, sizeof dist); dist[S] = 0;
    max_flow[S] = INF, max_flow[T] = 0; int f = 0, r = 0;
    marked[q[r++] = S] = 1; pre[T] = NULL;
    while (f - r)
    {
        int u = q[f++], v; marked[u] = 0, f &= SIZE;
        for (Edge* p = edge[u]; p; p = p -> next)
        if (p -> f > 0 && dist[u] + p -> d > dist[v = p -> v])
        {
            dist[v] = dist[u] + p -> d, pre[v] = p;
            max_flow[v] = std::min(max_flow[u], p -> f);
            if (!marked[v]) marked[q[r++] = v] = 1, r &= SIZE;
        }
    }
    for (Edge* p = pre[T]; p; p = pre[p -> u])
        p -> f -= max_flow[T], p -> op -> f += max_flow[T];
    return dist[T] * max_flow[T];
}

int main()
{
    freopen("Intervals.in", "r", stdin);
    freopen("Intervals.out", "w", stdout);
    scanf("%d", &t);
    while (t--)
    {
        scanf("%d%d", &n, &K); cnt = 0;
        for (int i = 0; i < n; ++i)
            scanf("%d%d%d", L + i, R + i, w + i),
            tab[cnt++] = L[i], tab[cnt++] = R[i];
        std::sort(tab, tab + cnt);
        cnt = std::unique(tab, tab + cnt) - tab;
        T = cnt + 2, S = 1;
        memset(edge, 0, sizeof edge); tot = __edge;
        for (int i = 0; i < n; ++i)
            L[i] = std::lower_bound(tab, tab + cnt, L[i]) - tab + 2,
            R[i] = std::lower_bound(tab, tab + cnt, R[i]) - tab + 2,
            Ins(L[i], R[i], 1, w[i]);
        for (int i = 1; i < cnt + 2; ++i) Ins(i, i + 1, K, 0);
        int tmp, ans = 0;
        while (tmp = Spfa()) ans += tmp;
        printf("%d\n", ans);
    }
    return 0;
}

/*

建模方法:
将所有区间离散化到2~M + 1,添加超级源S = 1, T = M + 2。
对所有的1 <= i <= M + 1到i + 1连一条容量为K,费用为0的边;
对所有的区间(Li, Ri),从Li`到Ri`连一条容量为1,费用为该区间费用的边。(其中Li`、Ri`分别为Li、Ri区间离散化过后对应的点。)

*/


你可能感兴趣的:(c,Date,网络,SAP,2010,Intervals)