[tyvj1982]武器分配

Description

后勤部队运来一批武器(机枪和盔甲)。你要把这些武器分配给手下的marine们(每人一部机枪,一套盔甲)。

可是问题来了。。。这些武器的型号不相同(武器是由出价最低的承包商制造的),把一部m型的机枪和一套n型的盔甲分配给一个marine得到的不满意值为(m-n)^2(每个marine当然希望自己得到的武器是同一型号的)。

你的任务就是把a部机枪和b套盔甲分配给手下n个marine。使他们的不满意值之和最小。

Input

第一行:3 个正整数 n , a , b (1<=n<=a,b<=80)

第二行:a 个数表示每部机枪的型号

第三行:b 个数表示每套盔甲的型号

0<=型号值<=10000

Output

输出一个数:最小不满意值。

Solution:

本题用费用流来写。

建模:首先,把每一个人与源点连起来 S -> person 容量:1 费用:0

把每一把枪都和所有的盔甲连起来,容量为1,费用为选择这两种的不满度

然后,再把每一件盔甲都与汇点相连,容量为1,费用为0

由于每一把枪和每一件盔甲都只能用一次,我们建立一个中转站tmp

把每个人和tmp相连,再把tmp和每一把枪相连,容量为1,费用为0

最后跑一遍费用流就行了

Code:

#include<bits/stdc++.h>
#define N 50001
#define inf 1926081700
using namespace std;
int n,a,b,cnt=1,tmp;
int S,T,head[N],gun[81];
struct Edge{int nxt,to,v,w;}edge[N];
void ins(int x,int y,int z,int w){
	edge[++cnt].nxt=head[x];
	edge[cnt].to=y;edge[cnt].v=z;
	edge[cnt].w=w;head[x]=cnt;
}
namespace Network_Flow{
	queue<int> q;
	int delta,maxflow,mincost;
	int vis[N],pre[N],dis[N];
	int spfa(){
		delta=inf;pre[T]=0;
		memset(vis,0,sizeof(vis));
		for(int i=1;i<=tmp;i++) dis[i]=inf;
		q.push(S);vis[S]=1;dis[S]=0;
		while(!q.empty()){
			int x=q.front();q.pop();vis[x]=0;
			for(int i=head[x];i;i=edge[i].nxt){
				int y=edge[i].to;
				if(edge[i].v&&dis[x]+edge[i].w<dis[y]){
					dis[y]=edge[i].w+dis[x];
					delta=min(delta,edge[i].v);
					pre[y]=i;if(!vis[y]) q.push(y),vis[y]=1;
				}
			}
		}
		return pre[T];
	}
	void update(){
		int x=T;
		while(x!=S){
			int u=pre[x];
			edge[u].v-=delta;
			edge[u^1].v+=delta;
			x=edge[u^1].to;
		}
		maxflow+=delta;mincost+=dis[T];
	}
	void Edmonds_Karp(){
		while(spfa()) update();
		printf("%d
",mincost);
	}
}
int read(){
	int x=0,f=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
	while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
	return x*f;
}
int main(){
	n=read(),a=read(),b=read();
	S=n+a+b+1,T=S+1,tmp=T+1;
	using namespace Network_Flow;
	for(int i=1;i<=n;i++)
		ins(S,i,1,0),ins(i,S,0,0);
	for(int i=1;i<=n;i++)
		ins(i,tmp,1,0),ins(tmp,i,0,0);
	for(int i=1;i<=a;i++){
		gun[i]=read();
		ins(tmp,i+n,1,0);
		ins(i+n,tmp,0,0);
	}
	for(int i=1;i<=b;i++){
		int x=read();
		for(int j=1;j<=a;j++){
			int y=x-gun[j];y*=y;
			ins(j+n,i+a+n,1,y);
			ins(i+a+n,j+n,0,-y);
		}
		ins(i+a+n,T,1,0);
		ins(T,i+a+n,0,0);
	}
	Edmonds_Karp();
	return 0;
}
原文地址:https://www.cnblogs.com/NLDQY/p/10342780.html