• 【费用流】【网络流24题】【P4014】 分配问题


    Description

    (n) 件工作要分配给 (n) 个人做。第 (i) 个人做第 (j) 件工作产生的效益为 (C_{i,j}) 。试设计一个将 (n) 件工作分配给 (n) 个人做的分配方案,使产生的总效益最大。

    Input

    文件的第 (1) 行有 (1) 个正整数 (n),表示有 (n) 件工作要分配给 (n) 个人做。

    接下来的 (n) 行中,每行有 (n) 个整数 (C_{i,j}),表示第 (i) 个人做第 (j) 件工作产生的效益为 (C_{ij})

    Output

    两行分别输出最小总效益和最大总效益。

    Hint

    (1~leq~n~leq~100)

    Solution

    先考虑最小收益,由于必须所有的工作都被分配,所以这个限制可以转化为最大流,由于是最小费用,所以可以转化成最小费用最大流。

    将人和工作之间连边,容量为 (1),费用为效益。建立超级源点超级汇点,源点连向人,容量为 (1),费用为 (0)。工作连向汇点,容量为 (1),费用为 (0)。这样保证了一个任务选且被选一次,同时费用即为收益。

    考虑最大收益:将所有费用取相反数,求出答案再取相反即可。

    Code

    #include <cstdio>
    #include <cstring>
    #include <queue>
    #include <algorithm>
    #ifdef ONLINE_JUDGE
    #define freopen(a, b, c)
    #endif
    #define ci const int
    #define cl const long long
    
    typedef long long int ll;
    
    namespace IPT {
    	const int L = 1000000;
    	char buf[L], *front=buf, *end=buf;
    	char GetChar() {
    		if (front == end) {
    			end = buf + fread(front = buf, 1, L, stdin);
    			if (front == end) return -1;
    		}
    		return *(front++);
    	}
    }
    
    template <typename T>
    inline void qr(T &x) {
    	char ch = IPT::GetChar(), lst = ' ';
    	while ((ch > '9') || (ch < '0')) lst = ch, ch=IPT::GetChar();
    	while ((ch >= '0') && (ch <= '9')) x = (x << 1) + (x << 3) + (ch ^ 48), ch = IPT::GetChar();
    	if (lst == '-') x = -x;
    }
    
    template <typename T>
    inline void ReadDb(T &x) {
    	char ch = IPT::GetChar(), lst = ' ';
    	while ((ch > '9') || (ch < '0')) lst = ch, ch = IPT::GetChar();
    	while ((ch >= '0') && (ch <= '9')) x = x * 10 + (ch ^ 48), ch = IPT::GetChar();
    	if (ch == '.') {
    		ch = IPT::GetChar();
    		double base = 1;
    		while ((ch >= '0') && (ch <= '9')) x += (ch ^ 48) * ((base *= 0.1)), ch = IPT::GetChar();
    	}
    	if (lst == '-') x = -x;
    }
    
    namespace OPT {
    	char buf[120];
    }
    
    template <typename T>
    inline void qw(T x, const char aft, const bool pt) {
    	if (x < 0) {x = -x, putchar('-');}
    	int top=0;
    	do {OPT::buf[++top] = static_cast<char>(x % 10 + '0');} while (x /= 10);
    	while (top) putchar(OPT::buf[top--]);
    	if (pt) putchar(aft);
    }
    
    const int maxn = 210;
    const int INF = 0x3f3f3f3f;
    
    struct Edge {
    	int from, to, flow, fee;
    	Edge *nxt, *bk;
    };
    Edge *hd[maxn], *pre[maxn];
    inline void cont(Edge *u, Edge *v, int from, int to, int fl, int fe) {
    	u->from = from; u->to = to; u->flow = fl; u->fee = fe; u->bk = v;
    	u->nxt = hd[from]; hd[from] = u;
    }
    inline void conet(int from, int to, int fl, int fe) {
    	Edge *u = new Edge, *v = new Edge;
    	cont(u, v, from, to, fl, fe); cont(v, u, to, from, 0, -fe);
    }
    
    int n, s, t, ans;
    int cost[maxn], maxflw[maxn], MU[maxn][maxn];
    bool inq[maxn];
    std::queue<int>Q;
    
    bool SPFA();
    void argu();
    
    int main() {
    	freopen("1.in", "r", stdin);
    	qr(n);
    	for (int i = 1; i <= n; ++i) {
    		for (int j = 1; j <= n; ++j) {
    			qr(MU[i][j]); conet(i, j + n, 1, MU[i][j]);
    		}
    	}
    	s = (n << 1) | 1; t = (n << 1) + 2;
    	for (int i = 1; i <= n; ++i) conet(s, i, 1, 0);
    	for (int i = n + 1; i < s; ++i) conet(i, t, 1, 0);
    	ans = 0;
    	while (SPFA()) argu();
    	qw(ans, '
    ', true);
    	memset(hd, 0, sizeof hd);
    	for (int i = 1; i <= n; ++i) {
    		for (int j = 1; j <= n; ++j) conet(i, j + n, 1, -MU[i][j]);
    	}
    	for (int i = 1; i <= n; ++i) conet(s, i, 1, 0);
    	for (int i = n + 1; i < s; ++i) conet(i, t, 1, 0);
    	ans = 0;
    	while (SPFA()) argu();
    	qw(-ans, '
    ', true);
    	return 0;
    }
    
    bool SPFA() {
    	memset(cost, 0x3f, sizeof cost);
    	memset(inq, 0, sizeof inq);
    	memset(pre, 0, sizeof pre);
    	memset(maxflw, 0, sizeof maxflw);
    	cost[s] = 0; Q.push(s); maxflw[s] = INF;
    	while (!Q.empty()) {
    		int h = Q.front(); Q.pop(); inq[h] = false;
    		if (!maxflw[h]) continue;
    		for (Edge *e = hd[h]; e; e = e->nxt) if (e->flow > 0) {
    			int to = e->to;
    			if (cost[to] > (cost[h] + e->fee)) {
    				cost[to] = cost[h] + e->fee;
    				maxflw[to] = std::min(maxflw[h], e->flow);
    				if (!inq[to]) Q.push(to);
    				inq[to] = true; pre[to] = e;
    			}
    		}
    	}
    	return cost[t] != INF;
    }
    
    void argu() {
    	for (Edge *e = pre[t]; e; e = pre[e->from]) {
    		e->flow -= maxflw[t];
    		e->bk->flow += maxflw[t];
    	}
    	ans += maxflw[t] * cost[t];
    }
    
  • 相关阅读:
    完全卸载Oracle方法、步骤
    使用oracle11g_instant_client来解决在不安装oracle客户端的情况下连接服务端
    Android系统中的6种模式
    现代汉语常用3500字
    debug1: Could not open authorized keys
    所选用户秘钥未在远程主机上注册
    directshow播放摄像头卡死问题
    linux设置静态IP
    gcc编译错误
    centos6.4编译gcc6.4
  • 原文地址:https://www.cnblogs.com/yifusuyi/p/10407687.html
Copyright © 2020-2023  润新知