题意:过年,一家人做家务,每个人做完每样家务会获得快乐值,每个人最多做家务的数量给予限制,求全家人的最大快乐值.
构图:费用流.源点向家庭成员连容量为家务数量的限制数,费用为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; }