Food
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 2664 Accepted Submission(s): 899
Problem Description
You, a part-time dining service worker in your college’s dining hall, are now confused with a new problem: serve as many people as possible.
The issue comes up as people in your college are more and more difficult to serve with meal: They eat only some certain kinds of food and drink, and with requirement unsatisfied, go away directly.
You have prepared F (1 <= F <= 200) kinds of food and D (1 <= D <= 200) kinds of drink. Each kind of food or drink has certain amount, that is, how many people could this food or drink serve. Besides, You know there’re N (1 <= N <= 200) people and you too can tell people’s personal preference for food and drink.
Back to your goal: to serve as many people as possible. So you must decide a plan where some people are served while requirements of the rest of them are unmet. You should notice that, when one’s requirement is unmet, he/she would just go away, refusing any service.
The issue comes up as people in your college are more and more difficult to serve with meal: They eat only some certain kinds of food and drink, and with requirement unsatisfied, go away directly.
You have prepared F (1 <= F <= 200) kinds of food and D (1 <= D <= 200) kinds of drink. Each kind of food or drink has certain amount, that is, how many people could this food or drink serve. Besides, You know there’re N (1 <= N <= 200) people and you too can tell people’s personal preference for food and drink.
Back to your goal: to serve as many people as possible. So you must decide a plan where some people are served while requirements of the rest of them are unmet. You should notice that, when one’s requirement is unmet, he/she would just go away, refusing any service.
Input
There are several test cases.
For each test case, the first line contains three numbers: N,F,D, denoting the number of people, food, and drink.
The second line contains F integers, the ith number of which denotes amount of representative food.
The third line contains D integers, the ith number of which denotes amount of representative drink.
Following is N line, each consisting of a string of length F. e jth character in the ith one of these lines denotes whether people i would accept food j. “Y” for yes and “N” for no.
Following is N line, each consisting of a string of length D. e jth character in the ith one of these lines denotes whether people i would accept drink j. “Y” for yes and “N” for no.
Please process until EOF (End Of File).
For each test case, the first line contains three numbers: N,F,D, denoting the number of people, food, and drink.
The second line contains F integers, the ith number of which denotes amount of representative food.
The third line contains D integers, the ith number of which denotes amount of representative drink.
Following is N line, each consisting of a string of length F. e jth character in the ith one of these lines denotes whether people i would accept food j. “Y” for yes and “N” for no.
Following is N line, each consisting of a string of length D. e jth character in the ith one of these lines denotes whether people i would accept drink j. “Y” for yes and “N” for no.
Please process until EOF (End Of File).
Output
For each test case, please print a single line with one integer, the maximum number of people to be satisfied.
Sample Input
4 3 3 1 1 1 1 1 1 YYN NYY YNY YNY YNY YYN YYN NNY
Sample Output
3
F种食物,N个人,D种饮料
先输入一排F个数字的是每种食物的量;
再输入D个数字是每种饮料的量;
然后N行 是每个人可以接受的食物是哪几种,第一个Y代表可以接受第一种食物
再N行,是每个人可以接受的饮料是哪几种,
每个人都只用给他一个食物或者饮料
做法是, 设一个超级源点beg, beg 连接到 各种食物, 权值是该食物的量.
然后把每个人拆开, 拆成 点头 和点尾,因为只吃一个,所以权值是1;
然后把这各种食物,根据每个人的爱好连接 到 人的点头,因为只吃一个,所以权值是1
在把每个人的点尾根据个人爱好,连接到 饮料,权值同理也是1;
再设一个超级汇点fin, 把各种饮料连接到 fin;
像这样建图
#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;
#define inf 1000000
#define N 1000
#define M 100000
//N为点数 M为边数 200 400 200
inline int Min(int a,int b){return a>b?b:a;} //注意这个类型是int
struct Edge{
int from, to, cap, nex;
}edge[M*2];//双向边,注意RE 注意这个模版是 相同起末点的边 同时有效而不是去重
int head[N],edgenum;//2个要初始化-1和0
void init()
{
memset(head,-1,sizeof(head));
edgenum=0;
}
void addedge(int u, int v, int cap){//网络流要加反向弧
Edge E = {u, v, cap, head[u]};
edge[ edgenum ] = E;
head[ u ] = edgenum++;
Edge E2 = {v, u, 0, head[v]}; //这里的cap若是单向边要为0
edge[ edgenum ] = E2;
head[ v ] = edgenum++;
}
int dis[N], cur[N];//dis[i]表示i点距离起点的距离 cur[i]表示i点所连接的边中 正在考虑的边 优化不再考虑已经用过的点 初始化为head
bool vis[N];
bool BFS(int Start,int End){//跑一遍最短路
memset(vis,0,sizeof(vis));
memset(dis,-1,sizeof(dis));
queue<int>Q;
Q.push(Start); dis[Start]=0; vis[Start]=1;
while(!Q.empty())
{
int u = Q.front(); Q.pop();
for(int i = head[u]; i != -1; i = edge[i].nex){
Edge E = edge[i];
if( !vis[E.to] && E.cap > 0)
{
vis[ E.to ] = true;
dis[ E.to ] = dis[ u ] + 1;
if(E.to == End) return true;
Q.push( E.to );
}
}
}
return false;
}
int DFS(int x, int a,int End){//当前 流入x 的流量是a 流量a 是所有流过边中 边权的最小值
if( x == End || a == 0)return a;
int flow = 0, f; //flow表示从x点流到下面所有点,最大的流量
for(int& i = cur[x]; i != -1; i = edge[i].nex)
{
Edge& E = edge[i];
if(dis[x] + 1 == dis[E.to] && (f = DFS(E.to , Min(a, E.cap), End))>0 )
{
E.cap -= f;
edge[ i^1 ].cap += f;//反向边要减掉
flow += f;
a -= f;
if(a==0)break;
}
}
return flow;
}
int Maxflow(int Start,int End){
int flow=0;
while(BFS(Start,End)){ //当存在源点到汇点的路径时
memcpy(cur,head,sizeof(head));//把head的数组复制过去
flow += DFS(Start, inf, End);
}
return flow;
}
int main()
{
int fin,beg;
int i,j,f,n,d,tem;
char a[300];
while(scanf("%d%d%d",&n,&f,&d)!=EOF)//f个点代表食物, 2*n个点代表人 d个点代表饮料
{
init();
fin=f+2*n+d+1;
beg=0;
for(i=1;i<=f;i++)
{
scanf("%d\n",&tem);
addedge(beg, i , tem);
}
for(i=1;i<=d;i++)
{
scanf("%d\n",&tem);
addedge(i+f+2*n, fin, tem);
}
for(i=1;i<=n;i++)
{
scanf("%s",a);
for(j=0;j<f;j++)
{
if(a[j]=='Y')
{
addedge( j+1, f+i , 1);//食物到人
}
}
addedge(f+i, f+i+n, 1);//人的量
}
for(i=1;i<=n;i++)//人
{
scanf("%s",a);
for(j=0;j<d;j++)
{
if(a[j]=='Y')
{
addedge(f+i+n, f+2*n+j+1,1);//人到饮料
}
}
}
printf("%d\n",Maxflow(beg,fin));
}
return 0;
}