题解 P2514 【[HAOI2010]工厂选址】

· · 题解

70分算法:费用流

#include <cstdio>

inline void read(int &x)
{
    static char ch; 
    while ((ch = getchar()) < '0' || ch > '9'); 
    x = ch - '0'; 
    while ((ch = getchar()) >= '0' && ch <= '9')
        x = (x << 3) + (x << 1) + ch - '0'; 
}

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

const int MaxN = 55; 
const int MaxM = 5e4 + 10; 
const int MaxB = 1e4 + 10; 
const int INF = 0x3f3f3f3f; 

const int MaxP = MaxM; 
const int MaxE = MaxP * 10; 

int dis[MaxP], src, des; 
int ect = 1, nxt[MaxE], to[MaxE], cap[MaxE], cst[MaxE], adj[MaxP], frm[MaxE], pre[MaxP]; 
int n, m, b, ans = 0, minAns = INF, ansNum; 
int h[MaxN], a[MaxM], c[MaxM][MaxN], tota; 

inline void addEdge(const int &u, const int &v, const int &c, const int &w)
{
    nxt[++ect] = adj[u], adj[u] = ect, to[ect] = v, frm[ect] = u, cap[ect] = c, cst[ect] = w; 
    nxt[++ect] = adj[v], adj[v] = ect, to[ect] = u, frm[ect] = v, cap[ect] = 0, cst[ect] = -w; 
}

inline bool SPFA()
{
    static int q[MaxE << 2], tail; 
    static bool inq[MaxP]; 
    for (int i = src; i <= des; ++i)
        dis[i] = INF; 
    inq[q[tail = 1] = src] = 1; 
    dis[src] = 0; 
    for (int head = 1, u, v, e; inq[u = q[head]] = 0, head <= tail; ++head)
        for (e = adj[u]; v = to[e], e; e = nxt[e])
            if (cap[e] > 0 && dis[v] > dis[u] + cst[e])
            {
                dis[v] = dis[u] + cst[e], pre[v] = e; 
                if (!inq[v])
                    inq[q[++tail] = v] = 1; 
            }
    return dis[des] != INF; 
}

inline void deal()
{
    int minFlow = INF; 
    for (int e = pre[des]; e; e = pre[frm[e]]) minFlow = getmin(minFlow, cap[e]); 
    for (int e = pre[des]; e; e = pre[frm[e]])
    {
        cap[e] -= minFlow; 
        cap[e ^ 1] += minFlow; 
        ans += minFlow * cst[e]; 
    }
}

int now; 
inline void MCMF()
{
    ans = 0; 
    while (SPFA()) deal(); 
    ans += h[0] + h[now]; 
    if (ans < minAns)
        minAns = ans, ansNum = now; 
}

inline void buildGraph()
{
    ect = 1; 
    for (int i = src; i <= des; ++i) adj[i] = 0, pre[i] = 0; 
    src = 0, des = m + 3; 
    for (int i = 1; i <= m; ++i)
        addEdge(src, i, a[i], 0), addEdge(i, m + 1, INF, c[i][0]), addEdge(i, m + 2, INF, c[i][now]); 
    addEdge(m + 1, des, b, 0), addEdge(m + 2, des, tota - b, 0); 
}

int main()
{
    read(m), read(b), read(h[0]), read(n); 
    for (int i = 1; i <= m; ++i) read(a[i]), tota += a[i]; 
    for (int i = 1; i <= n; ++i) read(h[i]); 
    for (int i = 0; i <= n; ++i)
        for (int j = 1; j <= m; ++j)
            read(c[j][i]); 
    for (now = 1; now <= n; ++now)
        buildGraph(), MCMF(); 
    printf("%d\n%d\n", ansNum, minAns); 
    return 0; 
}

100分算法:贪心

代码如下:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

typedef long long ll;
typedef unsigned long long ull;

int getintRes; 
inline int getint()
{
    static char ch; 
    while ((ch = getchar()) < '0' || ch > '9'); 
    getintRes = ch - '0'; 
    while ((ch = getchar()) >= '0' && ch <= '9')
        getintRes = getintRes * 10 + ch - '0'; 
    return getintRes; 
}

inline void read(int &x)
{
    static char ch; 
    while ((ch = getchar()) < '0' || ch > '9'); 
    x = ch - '0'; 
    while ((ch = getchar()) >= '0' && ch <= '9')
        x = x * 10 + ch - '0'; 
}

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

const int MaxN = 55; 
const int MaxM = 5e4 + 10; 
const int MaxB = 1e4 + 10; 
const int INF = ~0u >> 1; 

struct cyxPair
{
    int delta, count; 
    cyxPair() {}
    cyxPair(const int &d, const int &c):
        delta(d), count(c) {}
    inline bool operator < (const cyxPair &rhs) const
    {
        return delta < rhs.delta; 
    }
}c[MaxM]; 

int n, m, b; 
int a[MaxM], h[MaxN], c0[MaxM]; 
int minAns = INF, numAns; 

#define p(x, y) cyxPair(x, y)

int main()
{
    read(m), read(b), read(h[0]), read(n); 
    for (int i = 1; i <= m; ++i) read(a[i]); 
    for (int i = 1; i <= n; ++i) read(h[i]); 
    for (int i = 1; i <= m; ++i) read(c0[i]); 

    int totCount, totAns, tmp;  
    for (int now = 1; now <= n; ++now)
    {
        static int i; 
        totCount = b, totAns = 0; 
        for (i = 1; i <= m; ++i)
            read(tmp), c[i] = p(c0[i] - tmp, a[i]), totAns += tmp * a[i]; 
        std::sort(c + 1, c + m + 1); 
        for (i = 1; i <= m; ++i)
            if (totCount >= c[i].count)
                totCount -= c[i].count, totAns += c[i].delta * c[i].count; 
            else
                break; 
        if (totCount > 0)
            totAns += totCount * c[i].delta; //当我们有剩余的煤要送但不满该煤矿总量,我们也要将剩下的送出
        totAns += h[0] + h[now]; 
        if (totAns < minAns)
            minAns = totAns, numAns = now; 
    }
    printf("%d\n%d\n", numAns, minAns); 
    return 0; 
}