根據題意可以構建一個網路流模型
從源點到食物邊權為食物數量;
從第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;
}