網絡流\費用流\監控某批邊滿流的處理辦法(P1251 餐巾計劃問題)

題目鏈接
這個題想了半天.最後構建這樣一個模型:
對於N天
1.對每一天ii,拆點,拆成兩個(i,i+N)(i,i+N).中間連一條容量爲當天需要餐巾數量,費油爲0的邊<i,i+N,a[i],0><i,i+N,a[i],0>.
2.對於每天的後點,都往下一天連一條容量爲inf,費用爲0的邊<i+N,i+N+1,inf,0><i+N,i+N+1, inf, 0>
3.對於每一個後點,都往n和m天后的前點連一條容量爲inf,費用爲s或f的邊<i+N,i+m,inf,f><i+N, i+m, inf,f><i+N,i+n,inf,s><i+N,i+n,inf,s>
4.對於每一個前點,都往超級源點連一條邊<s,i,inf,p><s,i,inf,p>
這時顯然,我們必須監控:讓1中所連的邊跑到滿流的情況下,得出最小費…想了很久,最後得出一個監控一批邊滿流的實際方法:
對於想監控的那批邊<x,y,f,c><x,y,f,c>:
1.刪除原邊.
2.對於每一個邊我們向匯點連一條<x,t,f,c><x,t,f,c>
3.對於每一條邊我們從源點連一條<s,y,f,0><s,y,f,0>
然後從源點向匯點跑一個費用流,就可以得出在特定一批邊滿流後的最小費用了.
上述理論系本人自己琢磨出來,缺乏證明,缺乏證明,缺乏證明,正確性未知,但洛谷題已過…
下面是ac代碼:

#include <iostream>
#include <string>
#include <cstring>
#include <vector>
#include <cmath>
#include <queue>
#include <map>
#include <set>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#define ll long long
#define int ll
#define max(x, y) ((x)>(y)?(x):(y))
#define min(x, y) ((x)<(y)?(x):(y))
#define pr(x, y) make_pair((x), (y))
using namespace std;
const int N = 2e6+5;
const int M = 2e6+5;
const int inf = 0x3f3f3f3f;
int tot;
int mx, h[N], dis[N], pre[N];
int he[N], ne[M], ver[M], e[M], c[M];
void init(int n)
{
    mx = n;
    tot = 1;
}
void add(int x, int y, int w, int _c)
{
  //  cout << x << "->" << y << "::" << w << " " << _c << endl;
    ver[++tot] = y;
    ne[tot] = he[x];
    he[x] = tot;
    c[tot] = _c;
    e[tot] = w;

    ver[++tot] = x;
    ne[tot] = he[y];
    he[y] = tot;
    e[tot] = 0;
    c[tot] = -_c;
}
int EK(int s, int t, int f, int &flow)
{
    int res = 0;
    fill(h, h + 1 + mx, 0);
    while(f)
    {
        priority_queue<pair<int, int>, vector<pair<int, int> >, greater<pair<int, int> > > q;
        fill(dis, dis + 1 + mx, inf);
        dis[s] = 0; q.push(pr(0, s));
        while(q.size())
        {
            pair<int, int> now = q.top(); q.pop();
            int te = now.second;
            if (dis[te] < now.first) continue;
            for (int i = he[te]; i; i = ne[i])
            {
                if (e[i] > 0 && dis[ver[i]] > dis[te] + c[i] + h[te] - h[ver[i]])
                {
                    dis[ver[i]] = dis[te] + c[i] + h[te] - h[ver[i]];
                    pre[ver[i]] = i;
                    q.push(pr(dis[ver[i]], ver[i]));
                }
            }
        }
        if (dis[t] == inf) break;
        for (int i = 0; i <= mx; i++) h[i] += dis[i];
        int d = f;
        for (int i = pre[t]; i; i = pre[ver[i^1]]) d = min(d, e[i]);
        f -= d; flow += d; res += d * h[t];
        for (int i = pre[t]; i; i = pre[ver[i^1]])
        {e[i] -= d; e[i^1] += d;}
    }
    return res;
}
int su[N];
signed main()
{
    int n;
    cin >> n;
    int s = 0, t = (n << 1) + 1;
    init(t);
    for (int i = 1; i <= n; i++)
        scanf("%lld", &su[i]);
    int p, m, f, _n, _s;
    scanf("%lld%lld%lld%lld%lld", &p, &m, &f, &_n, &_s);
    for (int i = 1; i <= n; i++)
    {
        if (i != n) add(i + n, i + n + 1, inf, 0);
        add(s, i, inf, p);
        add(s, i + n, su[i], 0);
        add(i, t, su[i], 0);
        if (i + m <= n) add(i + n, i + m, inf, f);
        if (i + _n <= n) add(i + n, i + _n, inf, _s);
    }
    int flow = 0;
    int ans = EK(s, t, inf, flow);
    printf("%lld\n", ans);
    return 0;
 }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章