poj3281二分图转换成最大流

来源:互联网 发布:ubuntu 安装luajit 编辑:程序博客网 时间:2024/06/05 09:35
//题意:为他的牛准备F种食物和D种饮料,没有牛有自己喜欢的食物和饮料,每头牛
//只能分的一种食物和饮料,最多有多少牛同时获得喜欢食物和饮料
//思路:因为如果只分配食物那么二分图最大匹配能解决,这种只有最大流解决
//构造图可以吧牛结点分成2个,然后连一个容量为1的边,那么相当于只能选择一种食物

//248K 32MS



#include <iostream>#include <vector>using namespace std;#define  MAX_N 105#define  MAX_V 1005static int N,F,D;static bool likeF[MAX_N][MAX_N];//食物喜欢static bool likeD[MAX_N][MAX_N];//饮料喜欢//主意struct的时候必须写复制构造函数static class edge{public:edge(int t,int c,int r):to(t),cap(c),rev(r){}edge(){to = cap = rev = 0;}int to;int cap;int rev;};static vector<edge>G[MAX_V];//图邻接表static bool used[MAX_V];static void add_edge(int from,int to,int cap){edge e(to,cap,G[to].size());G[from].push_back(e);//而from到to的反向边是从to新加入一条边就是在G[to].size()索引处edge e1(from,0,G[from].size()-1);G[to].push_back(e1);//to 到from的反向边是刚加入的from到to边序号是G[from].size()-1}static int dfs(int v,int t,int f){if (v==t)return f;used[v] = true;for (int i=0;i<G[v].size();++i){edge&e = G[v][i];if (!used[e.to]&&e.cap>0){int d = dfs(e.to,t,min(f,e.cap));//寻找该条路径上的最小流if (d>0){e.cap-=d;G[e.to][e.rev].cap+=d;return d;}}}return 0;}//深度优先搜索复杂度为O(F*E)static int max_flow(int s,int t){int flow = 0;for (;;)//迭代每一次可行的路径{memset(used,0,sizeof(used));int f = dfs(s,t,0x3f3f3f);if (f==0)return flow;flow+=f;}}static void  solve(){//结点分类//食物一侧的牛0-N-1//饮料一侧的牛N-2N-1//2N-2N+F-1食物//2N+F-2N+F+D-1饮料//源点和汇点int s = N*2+F+D,t = s+1;//s和食物连边for (int i=0;i<F;++i) add_edge(s,N*2+i,1);//饮料和tfor (int i=0;i<D;++i)     add_edge(N*2+F+i,t,1);for (int i=0;i<N;++i){//食物一侧的牛和饮料一侧牛add_edge(i,N+i,1);for (int j=0;j<F;++j){if (likeF[i][j]) add_edge(N*2+j,i,1);}for (int j=0;j<D;++j)   if (likeD[i][j])    add_edge(N+i,N*2+F+j,1);}printf("%d\n",max_flow(s,t));}int main(){scanf("%d %d %d",&N,&F,&D);int fn,dn;for (int i=0;i<N;++i){scanf("%d %d",&fn,&dn);int like;for (int j=0;j<fn;++j){  scanf("%d",&like);  likeF[i][like-1] = true;}for (int j=0;j<dn;++j){  scanf("%d",&like);  likeD[i][like-1] = true;}}solve();return 0;}


0 0
原创粉丝点击