zoukankan      html  css  js  c++  java
  • JZOJ 3447.摘取作物

    ( ext{Problem})

    在一个矩阵里选数,每行最多选两个,每列最多选两个,最大会价值
    (n,m le 30)

    ( ext{Analysis})

    对个这个限制如何实现?
    跑费用流
    把行看做点,列看做点
    点对 ((i,j)) 就用 (i) 行点连向 (j) 列点,流量为 (1),费用为 (-v[i][j])
    原点向行点连一条流量为 (2),费用为 (0) 的边,列点向汇点连一条流量为 (2),费用为 (0) 的边
    这样就可以保证限制了
    因为跑 (spfa) 得到最小费用,但要注意不一定要最大流,可行流即可
    所以 (spfa) 后判断 (dis[T]) 的正负情况,决定是否继续

    ( ext{Code})

    #include<cstdio>
    #include<cstring>
    #include<queue>
    using namespace std;
    
    const int N = 905;
    int n , m , S = 0 , T, Maxflow , Mincost;
    int dis[N] , h[N] , vis[N] , pre[N] , edge[N] , flow[N] , tot = 1;
    
    queue<int> d;
    struct node{
    	int to , nxt , w , f;
    }e[N << 1 + 10];
    
    inline void add(int u , int v , int w , int f){e[++tot] = node{v, h[u], w, f}, h[u] = tot;}
    
    int spfa()
    {
    	memset(vis , 0 , sizeof(vis));
    	memset(dis , 127 , sizeof(dis));
    	memset(flow , 127 , sizeof(flow));
    	d.push(S);
    	vis[S] = 1 , dis[S] = 0 , pre[T] = -1;
    	while (!d.empty())
    	{
    		int now = d.front();
    		d.pop(), vis[now] = 0;
    		for(register int i = h[now]; i; i = e[i].nxt)
    		if (dis[e[i].to] > dis[now] + e[i].f && e[i].w)
    		{
    			dis[e[i].to] = dis[now] + e[i].f;
    			flow[e[i].to] = min(flow[now] , e[i].w);
    			pre[e[i].to] = now, edge[e[i].to] = i;
    			if (!vis[e[i].to]) vis[e[i].to] = 1 , d.push(e[i].to);
    		} 
    	}
    	return (dis[T] < 0 && pre[T] != -1);
    }
    
    int MCMF()
    {
    	while (spfa()) 
    	{
    		Maxflow += flow[T], Mincost += dis[T] * flow[T];
    		int now = T;
    		while (now != S)
    			e[edge[now]].w -= flow[T], e[edge[now] ^ 1].w += flow[T], now = pre[now];
    	}
    	return Mincost;
    }
    
    int main()
    {
    	freopen("pick.in", "r", stdin);
    	freopen("pick.out", "w", stdout);
    	scanf("%d%d", &n, &m), T = n + m + 1;
    	for(int i = 1, x; i <= n; i++)
    		for(int j = 1; j <= m; j++) scanf("%d", &x), add(i, j + n, 1, -x), add(j + n, i, 0, x);
    	for(int i = 1; i <= n; i++) add(S, i, 2, 0), add(i, S, 0, 0);
    	for(int j = 1; j <= m; j++) add(j + n, T, 2, 0), add(T, j + n, 0, 0);
    	printf("%d
    ", -MCMF());
    }
    
  • 相关阅读:
    selenium从入门到应用
    Maven 小技巧之 自动更新你的jar包
    selenium从入门到应用
    selenium从入门到应用
    沈逸老师PHP魔鬼特训笔记(8)
    PHP实现遍历、复制、删除目录
    沈逸老师PHP魔鬼特训笔记(7)--我叫什么名字
    PHP常用文件函数和目录函数整理
    沈逸老师PHP魔鬼特训笔记(6)--巫术与骨架
    沈逸老师PHP魔鬼特训笔记(5)
  • 原文地址:https://www.cnblogs.com/leiyuanze/p/15011094.html
Copyright © 2011-2022 走看看