您的位置:首页 > 其它

2011东北地区赛E题(最大费用最大流/二分图最大权匹配)

2012-06-03 19:33 579 查看
题意:过年,一家人做家务,每个人做完每样家务会获得快乐值,每个人最多做家务的数量给予限制,求全家人的最大快乐值.

构图:费用流.源点向家庭成员连容量为家务数量的限制数,费用为0的边,家务向终点连容量为1,费用为0的边,家庭成员向家务连容量为1,费用为-权值的边,

求最小费用最大流,取反.

View Code

#include <iostream>
#include <stdio.h>
#include <queue>
#include <math.h>
#include <string.h>
using namespace std;
#define V 5500
#define E 5007000
#define inf 0x3F3F3F3F
int n,m;
int vis[V];
int dist[V];
int pre[V];

struct Edge{
int u,v,c,cost,next;
}edge[E];
int head[V],cnt;
void init(){
cnt=0;
memset(head,-1,sizeof(head));
}

void addedge(int u,int v,int c,int cost){
edge[cnt].u=u;edge[cnt].v=v;edge[cnt].cost=cost;

edge[cnt].c=c;edge[cnt].next=head[u];head[u]=cnt++;

edge[cnt].u=v;edge[cnt].v=u;edge[cnt].cost=-cost;
edge[cnt].c=0;edge[cnt].next=head[v];head[v]=cnt++;
}

bool spfa(int begin,int end){
int u,v;
queue<int> q;

for(int i=0;i<=end+2;i++){
pre[i]=-1;
vis[i]=0;
dist[i]=inf;
}
vis[begin]=1;
dist[begin]=0;
q.push(begin);

while(!q.empty()){

u=q.front();
q.pop();
vis[u]=0;

for(int i=head[u];i!=-1;i=edge[i].next){
if(edge[i].c>0){
v=edge[i].v;
if(dist[v]>dist[u]+edge[i].cost){
dist[v]=dist[u]+edge[i].cost;
pre[v]=i;
if(!vis[v]){
vis[v]=true;
q.push(v);
}
}
}
}

}

return dist[end]!=inf;
}

int MCMF(int begin,int end){
int ans=0,flow;
int flow_sum=0;

while(spfa(begin,end)){

flow=inf;
for(int i=pre[end];i!=-1;i=pre[edge[i].u])
if(edge[i].c<flow)
flow=edge[i].c;
for(int i=pre[end];i!=-1;i=pre[edge[i].u]){
edge[i].c-=flow;
edge[i^1].c+=flow;
}
ans+=dist[end];
flow_sum+=flow;

}
return ans;
}

int main()
{
//freopen("in.txt","r",stdin);
int gain[50][30];
int afford[50];
while(cin >> n >> m){
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
cin >> gain[i][j];
for(int i=1;i<=n;i++)
cin >> afford[i];
init();
for(int i=1;i<=n;i++)
addedge(0,i,afford[i],0);
for(int i=n+1;i<=n+m;i++)
addedge(i,n+m+1,1,0);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
addedge(i,n+j,1,-gain[i][j]);
int res=MCMF(0,n+m+1);
printf("%d\n",-res);
}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: