zoukankan      html  css  js  c++  java
  • P1559 运动员最佳匹配问题 最大费用最大流

    P1559 运动员最佳匹配问题 费用流

    题目链接

    ​ 虽然思想不难, 但是写了好久, 原因是网络流都忘得差不多了, 这相当于复习了.

    ​ 最大费用最大流.

    ​ 炒鸡源点向男生连一条费用为0, 流量为1的边.女生向炒鸡汇点连一条费用为0,流量为1的边.所有男生向女生连一条费用为(p[i][j] * q[j][i]), 流量为1的边.

    ​ 流量都为1可以确保一个男生对应一个女生.思想挺简单的.

    #include <bits/stdc++.h>
    
    using namespace std;
    
    inline long long read() {
    	long long s = 0, f = 1; char ch;
    	while(!isdigit(ch = getchar())) (ch == '-') && (f = -f);
    	for(s = ch ^ 48;isdigit(ch = getchar()); s = (s << 1) + (s << 3) + (ch ^ 48));
    	return s * f;
    }
    
    const int N = 25;
    int n, s, t, ans, cnt;
    int in[N], dis[N], pre[N], incf[N], head[N], p[N][N], q[N][N];
    struct edge { int to, nxt, val, cost; } e[N * N + 2 * N]; 
    
    void add(int x, int y, int z, int f) {
    	e[++ cnt].nxt = head[x]; head[x] = cnt; e[cnt].to = y; e[cnt].val = z; e[cnt].cost = f;
    }
    
    int spfa() {
    	queue <int> q;
    	for(int i = 0;i <= t; i++) dis[i] = -1e9;
    	q.push(s); dis[s] = 0; in[s] = 1; incf[0] = 1e9;
    	while(!q.empty()) {
    		int x = q.front(); q.pop(); in[x] = 0;
    		for(int i = head[x]; i ; i = e[i].nxt) {
    			if(!e[i].val) continue;
    			int y = e[i].to; 
    			if(dis[y] < dis[x] + e[i].cost) {
    				dis[y] = dis[x] + e[i].cost; pre[y] = i;
    				incf[y] = min(incf[x], e[i].val);
    				if(!in[y]) in[y] = 1, q.push(y);
    			}
    		}
    	}
    	return dis[t] != -1e9;
    }
    
    void up() {
    	int p = t;
    	while(p != s) {
    		int i = pre[p];
    		e[i].val -= incf[t]; e[i ^ 1].val += incf[t];
    		p = e[i ^ 1].to;
    		ans += e[i].cost * incf[t];
    	}
    }
    
    int main() {
    
    	n = read(); s = 0, t = 2 * n + 1; cnt = 1;
    	for(int i = 1;i <= n; i++) for(int j = 1;j <= n; j++) p[i][j] = read();
    	for(int i = 1;i <= n; i++) for(int j = 1;j <= n; j++) q[i][j] = read();
    	for(int i = 1;i <= n; i++) add(s, i, 1, 0), add(i, s, 0, 0);
    	for(int i = n + 1;i <= 2 * n; i++) add(i, t, 1, 0), add(t, i, 0, 0);
    	for(int i = 1;i <= n; i++) 
    		for(int j = 1;j <= n; j++) add(i, j + n, 1, p[i][j] * q[j][i]), add(j + n, i, 0, -p[i][j] * q[j][i]);
    	while(spfa()) up();
    	printf("%d", ans);
    
    	return 0;
    }
    
  • 相关阅读:
    docker学习
    LIS是什么?
    Android网络课程笔记-----定制通知系统
    java常用算法
    java正则表达式大全
    无需ROOT就能拿ANR日志
    Android网络课程笔记-----定制系统控件2
    Android网络课程笔记-----定制系统控件1
    Android网络课程笔记-----Fragment
    读《启示录》有感-----1
  • 原文地址:https://www.cnblogs.com/czhui666/p/13974670.html
Copyright © 2011-2022 走看看