1. 程式人生 > 實用技巧 >hdu6787(根據喜歡程度分配得最大總價值,最大費用最大流)

hdu6787(根據喜歡程度分配得最大總價值,最大費用最大流)

題: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<<'\n'; } return 0; }
View Code