您的位置:首页 > 其它

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就能用剩下的糖果完成分配。

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