ACDream 1171 最大费用流,流量不一定最大

9 篇文章 0 订阅
1 篇文章 0 订阅


Click : 题目链接 

中文题。不翻译。

因为题目中问每行每列至少取多少个数,这是有下界最小费用流。。非常难搞。。 但可以转化一下,

从反的方向考虑。。就是每行每列最多取多少个, 这样反着建图,需要求的就是最大费用流了。

但需要注意的是, 这时候不需要满流, 因而需要对最大流最小费用流的模板的SPFA 写法进行改动。


我们在选择路径时,选择尽可能大的路径,这样才能保证费用最大。

然后其他建图就不难了。。

S连左边 n 个点 表示每行的限制, T连右边m个点表示列的限制

最后跑  SPFA 最大权路径的方式就OK了。。

要注意 dist 改成 -oo , 

#include <cstdio>  
#include <cstdlib>  
#include <map>  
#include <set>  
#include <algorithm>  
#include <cstring>  
#include <iostream>  
#include <vector>  
#include <string>  
#include <queue>  
#include <sstream>  
#include <math.h>  
  
#define mp(x,y) make_pair(x,y)  
#define pii pair<int,int>  
#define pLL pair<long long ,long long>  
#define pb(x) push_back(x)  
#define rep(i,j,k) for(int i = j; i < k;i++)  
  
#define MAX(x,a)  x=((x)<(a))?(a):(x);  
#define MIN(x,a)  x=((x)>(a))?(a):(x);  
  
using namespace std;  

int sumFlow;
const int MAXN = 502;
const int MAXM = 10002;
const int INF = 1000000000;
struct Edge
{
    int u, v, cap, cost;
    int next;
}edge[MAXM<<2];
int NE;
int head[MAXN], dist[MAXN], pp[MAXN];
bool vis[MAXN];
void init()
{
    NE = 0;
    memset(head, -1, sizeof(head));
}
void addedge(int u, int v, int cap, int cost)
{
    edge[NE].u = u; edge[NE].v = v; edge[NE].cap = cap; edge[NE].cost = cost;
    edge[NE].next = head[u]; head[u] = NE++;
    edge[NE].u = v; edge[NE].v = u; edge[NE].cap = 0; edge[NE].cost = -cost;
    edge[NE].next = head[v]; head[v] = NE++;
}
bool SPFA(int s, int t, int n)
{
    int i, u, v;
    queue <int> qu;
    memset(vis,false,sizeof(vis));
    memset(pp,-1,sizeof(pp));
    for(i = 0; i <= n; i++) dist[i] = -INF;
    vis[s] = true; dist[s] = 0;
    qu.push(s);
    while(!qu.empty())
    {
        u = qu.front(); qu.pop(); vis[u] = false;
        for(i = head[u]; i != -1; i = edge[i].next)
        {
            v = edge[i].v;
            if(edge[i].cap && dist[v] < dist[u] + edge[i].cost)
            {
                dist[v] = dist[u] + edge[i].cost;
                pp[v] = i;
                if(!vis[v])
                {
                    qu.push(v);
                    vis[v] = true;
                }
            }
        }
    }
    return dist[t] >= 0;
}
int MCMF(int s, int t, int n) // minCostMaxFlow
{
    int flow = 0; // 总流量
    int i, minflow, mincost;
    mincost = 0;
    while(SPFA(s, t, n))
    {
        minflow = INF+1 ;
        for(i = pp[t]; i != -1; i = pp[edge[i].u])
            if(edge[i].cap < minflow)
                minflow = edge[i].cap;
        flow += minflow;
        for(i = pp[t]; i != -1; i = pp[edge[i].u])
        {
            edge[i].cap -= minflow;
            edge[i^1].cap += minflow;
        }
        mincost += dist[t] * minflow;
    }
    sumFlow = flow; // 题目需要流量,用于判断
    return mincost;
}
int a[55][55];
int R[55],C[55];
int gg[55][55];
int main()
{
    int n, m;
    int u, v, c;
	int t;
	scanf("%d",&t);
    while (t--)
    {	
		scanf("%d%d", &n, &m);
        init();
        int S = 0;
        int T = n + m + 1;
		int ans = 0;
		rep(i,1,n+1)
			rep(j,1,m+1)
				scanf("%d",&a[i][j]), ans+=a[i][j];
		rep(i,1,n+1) scanf("%d",&R[i]);
		rep(i,1,m+1) scanf("%d",&C[i]);
        rep(i,1,n+1){
			addedge(S,i,m-R[i],0);
		}
		
		rep(i,1,m+1)
			addedge(i+n,T,n-C[i],0);
		int zz = NE;
		rep(i,1,n+1)
			rep(j,1,m+1){
				addedge(i,j+n,1,a[i][j]);
			}
		int sdf = NE;

		int cc=MCMF(S,T,T+1);
		ans -= cc;
		printf("%d\n",ans);
    }
    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值