HDU 4322 Candy 最大费用流+巧妙建图
2017-10-25 23:01
393 查看
单单用最大流显然是不能达到最佳分配的,应该使用费用流。
费用很显然,对于喜欢的糖,费用就是K,我一开始想的是用b[i]/k来表示容量上限,但后来发现这样是不对的,因为可能最后一颗糖加上之后费用超过了b[i],但实际得到的快乐值只有b[i],所以要对b[i]%k 进行讨论
1. 若b[i]%k==0 那么把连接人到超级汇点的边容量为b[i]/k,费用为k,即(b[i]/k,k)
2. 若b[i]%k!=0 那么分别连两条边即(b[i]/k,k)和(1,b[i]%k)
其它都是很正常的连边,即从超级源点到各个糖果,容量为1,费用为0。还有从糖果到喜欢这个糖果的人,容量为1,费用为0。
这样跑完最大费用最大流之后,得到maxcost和maxflow,分别表示当前的快乐值之和和使用糖果数,那么剩下的糖果都只能产生1的快乐值,所以如果tot(b[i])−maxcost≤n−maxflow就能用剩下的糖果完成分配。
费用很显然,对于喜欢的糖,费用就是K,我一开始想的是用b[i]/k来表示容量上限,但后来发现这样是不对的,因为可能最后一颗糖加上之后费用超过了b[i],但实际得到的快乐值只有b[i],所以要对b[i]%k 进行讨论
1. 若b[i]%k==0 那么把连接人到超级汇点的边容量为b[i]/k,费用为k,即(b[i]/k,k)
2. 若b[i]%k!=0 那么分别连两条边即(b[i]/k,k)和(1,b[i]%k)
其它都是很正常的连边,即从超级源点到各个糖果,容量为1,费用为0。还有从糖果到喜欢这个糖果的人,容量为1,费用为0。
这样跑完最大费用最大流之后,得到maxcost和maxflow,分别表示当前的快乐值之和和使用糖果数,那么剩下的糖果都只能产生1的快乐值,所以如果tot(b[i])−maxcost≤n−maxflow就能用剩下的糖果完成分配。
#include <iostream> #include <algorithm> #include <cstring> #include <cstdio> #include <queue> using namespace std; const int MAXN = 1000; const int MAXM = 1e5+100; const int INF = 0x3f3f3f3f; struct Edge { int to,cap,flow,cost,nex; Edge(int to,int cap,int flow,int cost,int nex):to(to),cap(cap),flow(flow),cost(cost),nex(nex) {} Edge() {} }edge[MAXM]; int head[MAXN],dis[MAXN],tol,pre[MAXN],b[MAXN],tot,n,m,k; bool vis[MAXN]; void init() { memset(head,-1,sizeof head); tol=tot=0; } void addedge(int u,int v,int cap,int cost) { edge[tol] = Edge(v,cap,0,cost,head[u]); head[u] = tol++; edge[tol] =Edge(u,0,0,-cost,head[v]); head[v] = tol++; } bool spfa(int s,int t) { memset(vis,0,sizeof vis); memset(dis,0x3f,sizeof dis); memset(pre,-1,sizeof pre); queue<int> que; que.push(s); dis[s]=0; while (!que.empty()) { int u=que.front();que.pop(); vis[u]=false; for (int i=head[u];~i;i=edge[i].nex) { int v=edge[i].to; if (edge[i].cap > edge[i].flow && dis[v] > dis[u] + edge[i].cost) { dis[v] = dis[u] + edge[i].cost; pre[v] = i; if (!vis[v]) { que.push(v); vis[v]=true; } } } } if (~pre[t]) return true; else return false; } int MCMF(int s,int t,int &cost) { int flow=0,f,tmp=0; cost=0; while (spfa(s,t)) { int tmp = INF; for (int i=pre[t];~i;i=pre[edge[i^1].to]) tmp=min(edge[i].cap-edge[i].flow,tmp); for (int i=pre[t];~i;i=pre[edge[i^1].to]) { edge[i].flow += tmp; edge[i^1].flow -= tmp; cost += tmp*edge[i].cost; } flow += tmp; } return flow; } int main() { int t; scanf("%d",&t); for (int tt=1;tt<=t;tt++) { init(); int tar=600; scanf("%d%d%d",&n,&m,&k);//1--n candy n+1--n+m man n+m+1--n+2m man' for (int i=1;i<=n;i++) addedge(0,i,1,0); for (int i=1;i<=m;i++) { scanf("%d",&b[i]); tot += b[i]; if (b[i] % k == 0) { addedge(n+i,tar,b[i]/k,-k); } else { addedge(n+i,tar,b[i]/k,-k); addedge(n+i,tar,1,-(b[i]%k)); } } for (int i=1;i<=m;i++) for (int j=1;j<=n;j++) { int tmp; scanf("%d",&tmp); if (tmp==1) addedge(j,n+i,1,0); } int maxcost; int maxflow=MCMF(0,tar,maxcost); maxcost=-maxcost; if (tot - maxcost <= n-maxflow) printf("Case #%d: YES\n",tt); else printf("Case #%d: NO\n",tt); } return 0; }
相关文章推荐
- hdu 4322 Candy(最大费用流)2012 Multi-University Training Contest 3
- HDU 4322 Candy 最大费用流
- hdu 4322 Candy 【最大费用最大流】
- hdu 4322 Candy 最大费用最大流
- HDU 4322 Candy (最大费用最大流)经典
- hdu 4322 Candy 费用流
- hdu 4322 最大费用流
- hdu 4322(最大费用最大流)
- hdu 4322 Candy 【多校3】【费用流】
- HDU 4322 最大费用最大流 2012 Multi-University Training Contest 3
- hdu 4322(最大费用最大流)
- hdu 4862 Jump(最大费用最大流,巧妙构图)
- hdoj 4322 Candy 【最大费用最大流】【经典题目】【最大流时 维护费用的最大效益】
- hdu 4322 (费用流,巧妙建图)
- hdu-4322-Candy-费用流
- hdu 4322 最大费用最大流
- hdu 4322 Candy 费用流
- hdu 3395(费用流,二分图的最大权匹配)
- HDU 3435 KM算法或者最小费用最大流
- hdu 6118 度度熊的交易计划 (最小费用最大流