网络流 HDOJ 4292

来源:互联网 发布:f35和歼20知乎 编辑:程序博客网 时间:2024/05/11 21:53

根据题意可以构建一个网络流模型

从源点到食物边权为食物数量;

从第i个人喜欢的食物到第i个人的节点1,边权为1

从第i个人节点1到第i个人节点2,边权为1,防止一个人选择了多次

从第i个人节点2到饮料,边权为1

从饮料到汇点,边权为饮料数量

构建如下图







#include<stdio.h>

#include<string.h>
#include<algorithm>
using namespace std;
#define MAX 1001
int last;
int map[MAX][MAX];


int f, d, n;
char str[211];


int que[MAX], num;
int inque[MAX];
int h[MAX];


int min(int a, int b)
{
return a < b ? a : b;
}




int dfs(int pre, int minx)
{
int a;
if(pre == last)
return minx;
for(int i = 0; i <= last; i ++)
{
if(map[pre][i] > 0 && h[i] == h[pre] + 1)
{
a = dfs(i, min(map[pre][i], minx));
if(a == 0)
continue;
map[pre][i] -= a;
map[i][pre] += a;
return a;
}
}
h[pre] = -1; //注意这里的优化,只要这个地方没有增流,那么在下次宽搜之前的dfs就没有必要搜这个节点了,标记一下
return 0;
}


int bfs()
{
int i;


num = 0;


memset(inque, 0, sizeof(inque));
que[num] = 0;
inque[0] = 1;
h[0] = 0;


int front = 0;


int w = 1, index = 1;


while(front <= num)
{
if(front == w)
{
index ++;
w = num + 1;
}
for(i = 0; i <= last; i ++)
{
if(map[que[front]][i] == 0)
continue;
if(inque[i])
continue;
que[++ num] = i;
inque[i] = 1;
h[i] = index;
if(i == last)
return 1; //注意只要宽搜搜得汇点到就一定有增流
}
front ++;
}
return 0; //搜不到就一定不会有增流
}


int maxFlow()
{
int result = 0;
int get;
while(bfs())
{
while(get = dfs(0, MAX))              // 这里少了一个while导致超时,因为存在很多不需要款搜的情况
result += get;
}
return result;
}


int main()
{
int i, j;
while(scanf("%d%d%d", &n, &f, &d) != EOF)
{
last = f + 2 * n + d + 1;
memset(map, 0, sizeof(map));//先开始构建图的时候以为只要一个人节点就可以了,后来发现这个节点可能被多次流过,所以加个节点,边权为1,可以防止这种情况发生
for(i = 1; i <= f; i ++)
scanf("%d", &map[0][i]);
for(i = 1; i <= d; i ++)
scanf("%d", &map[f + 2 * n + i][last]);
for(i = 1; i <= n; i ++)
{
scanf("%s", str + 1);
for(j = 1; j <= f; j ++)
{
if(str[j] == 'Y')
{
map[j][f + i] = 1;
}
}
}
for(i = 1; i <= n; i ++)
{
scanf("%s", str + 1);
for(j = 1; j <= d; j ++)
{
if(str[j] == 'Y')
{
map[f + n + i][f + 2 * n + j] = 1;
}
}
}
for(i = 1; i <= n; i ++)
map[f + i][f + n + i] = 1;
printf("%d\n", maxFlow());
}
return 0;
}
原创粉丝点击