题:http://acm.hdu.edu.cn/showproblem.php?pid=6779
题意:给定a,b,c三种饮料数目和n个人,每个人有喜欢的饮料排名,价值依次是1、2、3,(最多6种类型的人)问分配后得到的最大总价值是多少。
分析:建边:1、源点向6类人建容量为这一类人出现的数目,费用为0;
2、6类人分别向3种饮料建容量为无穷,费用为喜欢价值的负数;
3、3种饮料向汇点建容量为饮料数目,费用为0。
跑费用流。
#include<bits/stdc++.h> using namespace std; const int M=2e5+5; const int inf=0x3f3f3f3f; struct node{ int u,v,w,cost,nextt; }e[M]; int mincost; int head[M],cur[M],dis[M],vis[12],tot,s,t; void addedge(int u,int v,int w,int cost){ e[tot].u=u; e[tot].v=v; e[tot].w=w; e[tot].cost=cost; e[tot].nextt=head[u]; head[u]=tot++; e[tot].u=v; e[tot].v=u; e[tot].w=0; e[tot].cost=-cost; e[tot].nextt=head[v]; head[v]=tot++; } bool bfs(){ for(int i=0;i<=t;i++) dis[i]=inf; queue<int>que; que.push(s); dis[s]=0; while(!que.empty()){ int u=que.front(); que.pop(); vis[u]=0; for(int i=head[u];~i;i=e[i].nextt){ int v=e[i].v; if(e[i].w&&dis[u]+e[i].cost<dis[v]){ dis[v]=dis[u]+e[i].cost; if(!vis[v]){ vis[v]=1; que.push(v); } } } } return dis[t]!=inf; } int dfs(int u,int fl){ if(u==t) return fl; int ans=0; vis[u]=1; for(int i=cur[u];~i;i=e[i].nextt){ int v=e[i].v; if(dis[v]==dis[u]+e[i].cost&&!vis[v]&&e[i].w){ cur[u]=i; int x=dfs(v,min(e[i].w,fl-ans)); e[i].w-=x; e[i^1].w+=x; ans+=x; mincost+=x*e[i].cost; if(ans==fl) break; } } vis[u]=0; return ans; } void MCMF(){ while(bfs()){ for(int i=0;i<=t;i++) cur[i]=head[i]; dfs(s,inf); } } string tmp[]={"012","021","102","120","201","210"}; int drink[]={7,8,9}; map<string,int>mp; int a[4]; int main(){ int T; cin>>T; while(T--){ memset(head,-1,sizeof(head)); mp.clear(); mincost=0; int n; cin>>n>>a[0]>>a[1]>>a[2]; for(int i=1;i<=n;i++){ string s; cin>>s; mp[s]++; } s=0,t=10; for(int i=0;i<6;i++){ if(mp[tmp[i]]==0) continue; addedge(s,i+1,mp[tmp[i]],0); for(int j=0;j<3;j++){ addedge(i+1,drink[tmp[i][j]-'0'],inf,j-3); ///cout<<tmp[i][j]<<"!!"<<drink[j]<<endl; } } for(int i=0;i<3;i++) if(a[i]) addedge(drink[i],t,a[i],0); MCMF(); cout<<-mincost<<' '; } return 0; }