首页 > 代码库 > hdu 4292 Food 最大流+拆点

hdu 4292 Food 最大流+拆点

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.
 

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).
 

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;
}