时间限制: 2 s
空间限制: 256000 KB
题目等级 : 大师 Master
题目描述 Description
有n件工作要分配给n个人做。第i 个人做第j 件工作产生的效益为ij c 。试设计一个将
n件工作分配给n个人做的分配方案,使产生的总效益最大。
«编程任务:
对于给定的n件工作和n个人,计算最优分配方案和最差分配方案。
输入描述 Input Description
第1 行有1 个正整数n,表示有n件工作要分配给n 个人做。接下来的n 行中,每行有n 个整数 cij ,1≤i≤n,1≤j≤n,表示第i 个人做第j件工作产生的效益为cij
输出描述 Output Description
将计算出的最小总效益和最大总效益输出
样例输入 Sample Input
5
2 2 2 1 2
2 3 1 2 4
2 0 1 1 1
2 3 4 3 3
3 2 1 2 1
样例输出 Sample Output
5
14
建图很简单,将人和任务分开就行,超级源点连人,流量为1,费用为0,人与任务之间流量为INF,费用为该人做此任务的价值,任务和超级汇点之间流量为1,费用为0,做一遍最小费用流,然后把所有费用变负,算最小费用;
#include<cstdio>
#include<climits>
#include<cstring>
#include<vector>
#include<queue>
#include<iostream>
using namespace std;
#define N 205
#define INF INT_MAX/3*2
struct NetWork{
struct Edge{
int fr,to,cap,flow,cost;
};
vector<Edge> edge;vector<int> g[N];
int d[N*2],p[N*2],v[N][N],S,T;int n,m,cost;
void clear(){
for(int i=0;i<edge.size();i++) edge[i].flow=0,edge[i].cost*=-1;
}
void Add_Edge(int fr,int to,int cap,int flow,int cost){
edge.push_back(Edge{fr,to,cap,flow,cost});
edge.push_back(Edge{to,fr,0,flow,-cost});
m=edge.size();
g[fr].push_back(m-2);g[to].push_back(m-1);
}
bool SPFA(){
queue<int> q;bool b[N*2];
for(int i=0;i<=T;i++) d[i]=INF;memset(b,0,sizeof(b));
b[S]=true;q.push(S);d[S]=0;
while(!q.empty()){
int x=q.front();q.pop();b[x]=false;
for(int i=0;i<g[x].size();i++){
Edge &e=edge[g[x][i]];
if(e.cap>e.flow&&d[e.to]>d[x]+e.cost){
d[e.to]=d[x]+e.cost;p[e.to]=g[x][i];
if(!b[e.to]){b[e.to]=true;q.push(e.to);}
}
}
}
if(d[T]==INF) return false;
cost+=d[T];
for(int x=T;x!=S;x=edge[p[x]].fr){
edge[p[x]].flow+=1;
edge[p[x]^1].flow-=1;
}
return true;
}
void solve(){
scanf("%d",&n);S=0,T=n*2+1,cost=0;int x;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
scanf("%d",&x),Add_Edge(i,n+j,INF,0,x);
for(int i=1;i<=n;i++) Add_Edge(S,i,1,0,0),Add_Edge(n+i,T,1,0,0);
while(SPFA());
printf("%d\n",cost);
cost=0;clear();
while(SPFA());
printf("%d",-cost);
}
}s;
int main(){
s.solve();return 0;
}