【题解】Catering World Finals 2015 上下界费用流

Prelude

传送到Codeforces:0.0


Solution

板子题,在这里贴个板子。
这题面是smg?题面中有说每个点只能经过一次吗?是我瞎了吗?
因为这WA on test 27一个小时,烦死了,浪费时间。


Code

#include <cstring>
#include <algorithm>
#include <cstdio>
#include <queue>
#include <cassert>

using namespace std;
const int MAXN = 1000;
const int MAXM = 100000;
const int INF = 0x3f3f3f3f;
int _w;

int read() {
    int x;
    _w = scanf( "%d", &x );
    return x;
}

namespace MCMF {
    struct Edge {
        int u, v, c, f, w;
        Edge() {}
        Edge( int u, int v, int c, int f, int w ):
            u(u), v(v), c(c), f(f), w(w) {}
    };
    
    int n, m, s, t;
    int head[MAXN], nxt[MAXM];
    Edge edge[MAXM];
    
    void init( int _n ) {
        n = _n, m = 0;
        for( int i = 0; i < n; ++i )
            head[i] = -1;
    }
    void adde( int u, int v, int c, int w ) {
        edge[m] = Edge(u, v, c, 0, w);
        nxt[m] = head[u], head[u] = m++;
        edge[m] = Edge(v, u, 0, 0, -w);
        nxt[m] = head[v], head[v] = m++;
    }
    
    queue<int> q;
    int dis[MAXN], inq[MAXN], res[MAXN], from[MAXN];
    
    bool spfa() {
        for( int i = 0; i < n; ++i )
            dis[i] = INF, inq[i] = 0;
        dis[s] = 0, inq[s] = 1, q.push(s), res[s] = INF;
        while( !q.empty() ) {
            int u = q.front(); q.pop();
            inq[u] = 0;
            for( int i = head[u]; ~i; i = nxt[i] ) {
                const Edge &e = edge[i];
                if( e.c > e.f && dis[u] + e.w < dis[e.v] ) {
                    dis[e.v] = dis[u] + e.w;
                    from[e.v] = i;
                    res[e.v] = min( res[u], e.c-e.f );
                    if( !inq[e.v] )
                        inq[e.v] = 1, q.push(e.v);
                }
            }
        }
        return dis[t] != INF;
    }
    void augment() {
        int f = res[t], u = t;
        while( u != s ) {
            int i = from[u];
            edge[i].f += f;
            edge[i^1].f -= f;
            u = edge[i].u;
        }
    }
    int solve( int _s, int _t ) {
        s = _s, t = _t;
        int cost = 0;
        while( spfa() ) {
            cost += res[t] * dis[t];
            augment();
        }
        return cost;
    }
}

int n, k, g[MAXN][MAXN];
int s, t, ss, tt, nid;
int in[MAXN], out[MAXN];

void adde( int u, int v, int l, int r, int w ) {
    MCMF::adde(ss, v, l, 0);
    MCMF::adde(u, tt, l, 0);
    MCMF::adde(u, v, r-l, w);
}

void solve() {
    s = nid++, t = nid++, ss = nid++, tt = nid++;
    for( int i = 1; i <= n; ++i )
        in[i] = nid++, out[i] = nid++;
    MCMF::init(nid);
    adde(t, s, 0, INF, 0);
    adde(s, out[1], 0, k, 0);
    for( int i = 2; i <= n; ++i ) {
        adde(out[i], t, 0, INF, 0);
        adde(in[i], out[i], 1, 1, 0); // 每个点只能经过一次
    }
    for( int i = 1; i <= n; ++i )
        for( int j = i+1; j <= n; ++j )
            adde(out[i], in[j], 0, INF, g[i][j]);
    printf( "%d\n", MCMF::solve(ss, tt) );
}

int main() {
    n = read()+1, k = read();
    for( int i = 1; i <= n; ++i )
        for( int j = i+1; j <= n; ++j )
            g[i][j] = read();
    solve();
    return 0;
}

转载于:https://www.cnblogs.com/mlystdcall/p/8137626.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值