zoukankan      html  css  js  c++  java
  • Luogu P4014 分配问题 题解

    闲扯

    蒟蒻的第一道自己想出怎么建图的题!!虽然是一个没什么技术含量的图 想了想,还是写篇题解纪念一下。

    题面

    题面

    Solution

    要求最小费用和最大费用,同时限制了流量,考虑费用流。

    虚拟一个超级源点,从这个点分别向 (N) 个任务连一条流量为 (1) ,费用为 (0) 的边。

    虚拟一个超级汇点,才从 (N) 个物品分别向该点连一条流量为 (1) ,费用为 (0) 的边。

    因为每个人只能做一件,且每个工作只能做一次,所以连的边流量都为一。而第 (i) 个人做第 (j) 个任务获得的贡献为 (val_{i,j}) ,所以从第 (j) 个物品向第 (i) 个人连一条费用为 (val_{i,j}) 的边。

    如果是求最小费用最大流,那么直接跑模板。

    如果是求最大费用最大流,只需要连边时将费用换为负数,求一个最小费用最大流,然后答案再取一个相反数即可。(这个处理好秒啊,自己没想出来,还是看了题解)

    Code

    #include<bits/stdc++.h>
    #define del(a,i) memset(a,i,sizeof(a))
    #define ll long long
    #define inl inline
    #define il inl void
    #define it inl int
    #define ill inl ll
    #define re register
    #define ri re int
    #define rl re ll
    #define mid ((l+r)>>1)
    #define lowbit(x) (x&(-x))
    #define INF 0x3f3f3f3f
    using namespace std;
    template<class T>il read(T &x){
    	int f=1;char k=getchar();x=0;
    	for(;k>'9'||k<'0';k=getchar()) if(k=='-') f=-1;
    	for(;k>='0'&&k<='9';k=getchar()) x=(x<<3)+(x<<1)+k-'0';
    	x*=f;
    }
    template<class T>il print(T x){
    	if(x/10) print(x/10);
    	putchar(x%10+'0');
    }
    ll mul(ll a,ll b,ll mod){long double c=1.;return (a*b-(ll)(c*a*b/mod)*mod)%mod;}
    it qpow(int x,int m,int mod){
    	int res=1,bas=x%mod;
    	while(m){
    		if(m&1) res=(res*bas)%mod;
    		bas=(bas*bas)%mod,m>>=1;
    	}
    	return res%mod;
    }
    int n,s,t,head[205],num_edge=-1,pre[205],last[205],flow[205],dis[205],mn_cost,val[105][105];
    struct Edge{
    	int next,to,w,c;
    	Edge(){}
    	Edge(int next,int to,int w,int c):next(next),to(to),w(w),c(c){}
    }edge[30000];
    il add_edge(int u,int v,int w,int c){
    	edge[++num_edge]=Edge(head[u],v,w,c),head[u]=num_edge;
    	edge[++num_edge]=Edge(head[v],u,0,-c),head[v]=num_edge;
    }
    bool tr[205];
    inl bool SPFA(int s,int t){
    	queue<int> q;q.push(s);
    	del(dis,0x3f),del(flow,0x3f);
    	dis[s]=0,pre[t]=-1,tr[s]=1;
    	while(!q.empty()){
    		ri pos=q.front();q.pop(),tr[pos]=0;
    		for(ri i=head[pos];i!=-1;i=edge[i].next)
    			if(dis[edge[i].to]>dis[pos]+edge[i].c&&edge[i].w>0){
    				dis[edge[i].to]=dis[pos]+edge[i].c;
    				pre[edge[i].to]=pos,last[edge[i].to]=i;
    				flow[edge[i].to]=min(flow[pos],edge[i].w);
    				if(!tr[edge[i].to]) q.push(edge[i].to),tr[edge[i].to]=1;
    			}
    	}
    	return pre[t]!=-1;
    }
    il MCMF(int s,int t){
    	while(SPFA(s,t)){
    		mn_cost+=dis[t]*flow[t];
    		for(ri u=t;u^s;u=pre[u]) edge[last[u]].w-=flow[t],edge[last[u]^1].w+=flow[t];
    	}
    }
    int main()
    {
    //	freopen(".in","r",stdin);
    //	freopen(".out","w",stdout);
    	read(n),del(head,-1),t=2*n+1;
    	for(ri i=1;i<=n;++i)
    		for(ri j=1;j<=n;++j){
    			read(val[i][j]);
    			add_edge(j,i+n,1,val[i][j]);
    		}
    	for(ri i=1;i<=n;++i) add_edge(s,i,1,0);
    	for(ri i=1;i<=n;++i) add_edge(i+n,t,1,0);
    	MCMF(s,t);
    	printf("%d
    ",mn_cost);
    	del(head,-1),num_edge=-1,mn_cost=0;
    	for(ri i=1;i<=n;++i)
    		for(ri j=1;j<=n;++j)
    			add_edge(j,i+n,1,-val[i][j]);
    	for(ri i=1;i<=n;++i) add_edge(s,i,1,0);
    	for(ri i=1;i<=n;++i) add_edge(i+n,t,1,0);
    	MCMF(s,t);
    	printf("%d",-mn_cost);
    	return 0;
    }
    

    总结

    这道题就是一个板子题,用来入门外加熟悉模板的。

    网络流的建图方式千千万,真的好神奇的,不要满足于现在的成就,还是要多练题,找到自己做网络流的套路呢~~

  • 相关阅读:
    DotnetBrowser入门教程-(2)启动简单的Web服务
    DotnetBrowser入门教程-(1)浏览器控件使用
    Delphi初始化与结束化
    用友二次开发之用友备份专家[1.01]
    用友账套恢复工具
    用友二次开发之总账自定义结转
    用友二次开发之登陆界面
    用友二次开发之U810.1销售预订单导入
    表格控件表头栏目(Column)与数据表头步
    Delphi开发的IP地址修改工具
  • 原文地址:https://www.cnblogs.com/TheShadow/p/11370196.html
Copyright © 2011-2022 走看看