zoukankan      html  css  js  c++  java
  • [TJOI2014]匹配

    \(\text{Solution}\)

    模板题,二分图带权匹配
    第一问费用流即可
    第二问考虑枚举最优方案的一条边,删掉,再跑费用流,不能跑出之前的结果说明此边为必经边

    \(\text{Code}\)

    #include <cstdio>
    #include <queue>
    #define RE register
    #define IN inline
    using namespace std;
    
    const int N = 165, INF = 5001;
    int n, m, S, T, ansflow, anscost;
    int pre[N], edge[N], dis[N], flow[N], vis[N], w[N][N], g[N][N], a[N][N], b[N][N], c[N][N];
    queue<int> Q;
    
    IN int spfa()
    {
    	for(RE int i = S; i <= T; i++) dis[i] = -INF, flow[i] = INF, vis[i] = 0;
    	dis[S] = 0, vis[S] = 1, Q.push(S), pre[T] = -1;
    	while (!Q.empty())
    	{
    		int now = Q.front(); Q.pop();
    		for(RE int i = S; i <= T; i++)
    		if (w[now][i] && dis[now] + b[now][i] > dis[i])
    		{
    			dis[i] = dis[now] + b[now][i], pre[i] = now, flow[i] = min(flow[now], w[now][i]);
    			if (!vis[i]) vis[i] = 1, Q.push(i);
    		}
    		vis[now] = 0;
    	}
    	return pre[T] != -1;
    }
    IN int MCMF(int ty)
    {
    	int Maxflow = 0, Mincost = 0;
    	while (spfa())
    	{
    		Maxflow += flow[T], Mincost += dis[T] * flow[T];
    		int now = T;
    		while (now != S) w[pre[now]][now] -= flow[T], w[now][pre[now]] += flow[T], now = pre[now];
    		if (Maxflow == n) break;
    	}
    	if (ty) ansflow = Maxflow, anscost = Mincost;
    	else return ((Maxflow == ansflow) && (Mincost == anscost));
    }
    
    int main()
    {
    	freopen("match.in", "r", stdin), freopen("match.out", "w", stdout);
    	scanf("%d", &n), S = 0, T = n + n + 1;
    	for(RE int i = 1; i <= n; i++)
    		for(RE int j = 1; j <= n; j++)
    			scanf("%d", &a[i][j + n]), a[j + n][i] = -a[i][j + n], g[i][j + n] = 1;
    	for(RE int i = 1; i <= n; i++) g[S][i] = 1, g[i + n][T] = 1;
    	for(RE int k = S; k <= T; k++)
    		for(RE int l = S; l <= T; l++) w[k][l] = g[k][l], b[k][l] = a[k][l];
    	MCMF(1), printf("%d\n", anscost);
    	for(RE int k = S; k <= T; k++)
    		for(RE int l = S; l <= T; l++) c[k][l] = w[k][l];
    	for(RE int i = 1; i <= n; i++)
    		for(RE int j = 1; j <= n; j++)
    		if (!c[i][j + n])
    		{
    			for(RE int k = S; k <= T; k++)
    				for(RE int l = S; l <= T; l++) w[k][l] = g[k][l], b[k][l] = a[k][l];
    			w[i][j + n] = 0, b[i][j + n] = -INF;
    			if (!MCMF(0)) printf("%d %d\n", i, j);
    		}
    }
    
  • 相关阅读:
    Coding Souls团队第二阶段冲刺(三)
    Coding Souls团队第二阶段冲刺(二)
    第一阶段意见评价
    PHPMailer/PHPMailer的使用
    使用jquery.media.js实现pdf在线预览
    select2(前端选择框_框架)
    安装Docker CE+阿里云镜像仓库
    docker学习
    前端开发框架WeUI
    php _Markdown转HTML
  • 原文地址:https://www.cnblogs.com/leiyuanze/p/15801826.html
Copyright © 2011-2022 走看看