1. 程式人生 > >誌願者招募 HYSBZ - 1061(公式建圖費用流)

誌願者招募 HYSBZ - 1061(公式建圖費用流)

找到 bitset size eof 除了 分享圖片 rep 資源 trie

轉自神犇:https://www.cnblogs.com/jianglangcaijin/p/3799759.html

題意:申奧成功後,布布經過不懈努力,終於 成為奧組委下屬公司人力資源部門的主管。布布剛上任就遇到了一個難題:為即將啟動的奧運新項目招募一批短期誌願者。經過估算,這個項目需要N 天才能完成,其中第i 天至少需要Ai 個人。 布布通過了解得知,一共有M 類誌願者可以招募。其中第i 類可以從第Si 天工作到第Ti 天,招募費用是每人Ci 元。新官上任三把火,為了出色地完成自己的工作,布布希望用盡量少的費用招募足夠的誌願者,但這並不是他的特長!於是布布找到了你,希望你幫他設計一種最 優的招募方案。

思路:

這個一個類影響一個區間,所以並不能像HDU - 3572 一樣 按時間拆點

所以列出公式求解

例如一共需要4天,四天需要的人數依次是4,2,5,3。有5類誌願者,如下表所示:

技術分享圖片

設雇傭第i類誌願者的人數為X[i],每個誌願者的費用為V[i],第j天雇傭的人數為P[j],則每天的雇傭人數應滿足一個不等式,如上表所述,可以列出

P[1]=X[1]+X[2]>=4

P[2]=X[1]+X[3]>=2

P[3]=X[3]+X[4]+X[5]>=5

P[4]=X[5]>=3

對於第i個不等式,添加輔助變量Y[i](Y[i]>=0),可以使其變為等式

P[1]=X[1]+X[2]-Y[1]=4

P[2]=X[1]+X[3]-Y[2]=2

P[3]=X[3]+X[4]+X[5]-Y[3]=5

P[4]=X[5]-Y[4]=3

在上述四個等式上下添加P[0]=0,P[5]=0,每次用下邊的式子減去上邊的式子,得出

① P[1]-P[0]=X[1]+X[2]-Y[1]=4

② P[2]-P[1]=X[3]-X[2]-Y[2]+Y[1]=-2

③ P[3]-P[2]=X[4]+X[5]-X[1]-Y[3]+Y[2]=3

④ P[4]-P[3]=-X[3]-X[4]+Y[3]-Y[4]=-2

⑤ P[5]-P[4]=-X[5]+Y[4]=-3

觀察發現,每個變量都在兩個式子中出現了,而且一次為正,一次為負.所有等式右邊和為0.我們將最後的五個等式進一步變形,得出以下結果

① -X[1]-X[2]+Y[1]+4=0

② -X[3]+X[2]+Y[2]-Y[1]-2=0

③ -X[4]-X[5]+X[1]+Y[3]-Y[2]+3=0

④ X[3]+X[4]-Y[3]+Y[4]-2=0

⑤ X[5]-Y[4]-3=0

可 以發現,每個等式左邊都是幾個變量和一個常數相加減,右邊都為0,恰好就像網絡流中除了源點和匯點的頂點都滿足流量平衡。每個正的變量相當於流入該頂點的 流量,負的變量相當於流出該頂點的流量,而正常數可以看作來自附加源點的流量,負的常數是流向附加匯點的流量。因此可以據此構造網絡,求出從附加源到附加 匯的網絡最大流,即可滿足所有等式。而我們還要求費用最小,所以要在X變量相對應的邊上加上權值,然後求最小費用最大流。

接下來,根據上面五個等式構圖。

(1)每個等式為圖中一個頂點,添加源點S和匯點T。

(2)如果一個等式中的數字為非負整數c,從源點S向該等式對應的頂點連接一條容量為c,權值為0的有向邊;如果為負整數-c,從該等式對應的頂點向匯點T連接一條容量為c,權值為0的有向邊。

(3)如果一個變量X[i]在第j個等式中出現為-X[i],在第k個等式中出現為+X[i],從頂點j向頂點k連接一條容量為INF,權值為V[i]的有向邊。

(4)如果一個變量Y[i]在第j個等式中出現為-Y[i],在第k個等式中出現為+Y[i],從頂點j向頂點k連接一條容量為INF,權值為0的有向邊。

構圖以後,求從源點S到匯點T的最小費用最大流,費用值就是結果。

#include <iostream>
#include <cstdio>
#include <sstream>
#include <cstring>
#include <map>
#include <cctype>
#include <set>
#include <vector>
#include <stack>
#include <queue>
#include <algorithm>
#include <cmath>
#include <bitset>
#define rap(i, a, n) for(int i=a; i<=n; i++)
#define rep(i, a, n) for(int i=a; i<n; i++)
#define lap(i, a, n) for(int i=n; i>=a; i--)
#define lep(i, a, n) for(int i=n; i>a; i--)
#define rd(a) scanf("%d", &a)
#define rlld(a) scanf("%lld", &a)
#define rc(a) scanf("%c", &a)
#define rs(a) scanf("%s", a)
#define rb(a) scanf("%lf", &a)
#define rf(a) scanf("%f", &a)
#define pd(a) printf("%d\n", a)
#define plld(a) printf("%lld\n", a)
#define pc(a) printf("%c\n", a)
#define ps(a) printf("%s\n", a)
#define MOD 2018
#define LL long long
#define ULL unsigned long long
#define Pair pair<int, int>
#define mem(a, b) memset(a, b, sizeof(a))
#define _  ios_base::sync_with_stdio(0),cin.tie(0)
//freopen("1.txt", "r", stdin);
using namespace std;
const int maxn = 1e5 + 10, INF = 0x7fffffff, LL_INF = 0x7fffffffffffffff;
int n, m, s, t;
int head[maxn], d[maxn], vis[maxn], nex[maxn], f[maxn], p[maxn], cnt;
int xu[maxn], flow, value;

struct node
{
    int u, v, w, c;
}Node[maxn];

void add_(int u, int v, int w, int c)
{
    Node[cnt].u = u;
    Node[cnt].v = v;
    Node[cnt].w = w;
    Node[cnt].c = c;
    nex[cnt] = head[u];
    head[u] = cnt++;
}

void add(int u, int v, int w, int c)
{
    add_(u, v, w, c);
    add_(v, u, -w, 0);
}

int spfa()
{
    for(int i = 0; i < maxn; i ++) d[i] = INF;
    deque<int> Q;
    mem(vis, 0);
    mem(p, -1);
    Q.push_front(s);
    d[s] = 0;
    p[s] = 0, f[s] = INF;
    while(!Q.empty())
    {
        int u = Q.front(); Q.pop_front();
        vis[u] = 0;
        for(int i = head[u];i != -1; i = nex[i])
        {
            int v = Node[i].v;
            if(Node[i].c)
            {
                if(d[v] > d[u] + Node[i].w)
                {
                    d[v] = d[u] + Node[i].w;
                    p[v] = i;
                    f[v] = min(f[u], Node[i].c);
                    if(!vis[v])
                    {
                      //  cout << v << endl;
                        if(Q.empty()) Q.push_front(v);
                        else
                        {
                            if(d[v] < d[Q.front()]) Q.push_front(v);
                            else Q.push_back(v);
                        }
                        vis[v] = 1;
                    }
                }
            }
        }
    }
    if(p[t] == -1) return 0;
    flow += f[t], value += f[t] * d[t];
   // cout << value << endl;
    for(int i = t; i != s; i = Node[p[i]].u)
    {
        Node[p[i]].c -= f[t];
        Node[p[i] ^ 1].c += f[t];
    }
    return 1;
}

void max_flow()
{
    flow = value = 0;
    while(spfa());
    pd(value);
}

void init()
{
    mem(head, -1);
    cnt = 0;
}

int main()
{
    init();
    int u, v, w;
    rd(n), rd(m);
    s = 0, t = n + 3;
    for(int i = 1; i <= n; i++)
    {
        rd(xu[i]);
    }
    for(int i = 1; i <= m; i++)
    {
        rd(u), rd(v), rd(w);
        add(u, v + 1, w, INF);
    }
    for(int i = 1; i <= n+1; i++)
    {
        int tmp = xu[i] - xu[i - 1];
        if(tmp > 0) add(s, i, 0, tmp);
        else add(i, t, 0, -tmp);
        if(i > 1) add(i, i - 1, 0, INF);
    }
    max_flow();


    return 0;
}

誌願者招募 HYSBZ - 1061(公式建圖費用流)