hdu 4292 最大流拆点建图
/* 题意:F种食物和D种饮料,每种食物和饮料的数目也是固定的,总共有N位顾客,每位顾客都只吃喝固定种类的食品 饮料,问最多能满足多少为顾客。 题解:最大流+拆点; 建图:将每位顾客拆成两个点,同一顾客之间加入权值为1的有向边限制了只能是一位一位顾客来满足,再加入源点 来连接每一种食物,权值为该食物数量,然后根据顾客喜欢的食物连接顾客,权值为1,因为每位顾客只需1份食物饮 料,然后加入饮料结点并根据顾客喜好连接,权值同样为1,然后将饮料与汇点连接,权值为饮料的数目,最终求得 的最大流即为最多能满足的顾客。 */ #include <cstdio> #include <cstring> #define EMAX 200000 #define VMAX 1005 const int INF = 0xfffffff; int head[VMAX],dis[VMAX],cur[VMAX],gap[VMAX],pre[VMAX]; int EN; struct edge { int from,to; int weight; int next; }e[EMAX]; void insert(int u,int v,int w) { e[EN].to = v; e[EN].weight = w; e[EN].next = head[u]; head[u] = EN++; e[EN].weight = 0; e[EN].to = u; e[EN].next = head[v]; head[v] = EN++; } int sap(int s,int t, int n) { memset(dis,0,sizeof(dis)); memset(gap,0,sizeof(gap)); for(int i=0; i<=n; i++) cur[i] = head[i]; int u = pre[s]; pre[s] = s; int ret = 0; int temp = -1; gap[0] = n; bool flag; while(dis[s] < n) { flag = false; for(int &i = cur[u]; i != -1; i = e[i].next) { int v = e[i].to; if(e[i].weight && dis[u] == dis[v] + 1) { if (temp == -1 || temp>e[i].weight) temp = e[i].weight; pre[v] = u; u = v; if(v == t) { ret += temp; for(u = pre[u];v != s;v = u,u = pre[u]) { e[cur[u]].weight -= temp; e[cur[u]^1].weight += temp; } temp = -1; } flag = true; break; } } if (flag) continue; int mindis = n; for(int i = head[u]; i != -1 ; i = e[i].next) { int v = e[i].to; if(e[i].weight && mindis > dis[v]) { cur[u] = i; mindis = dis[v]; } } gap[dis[u]]--; if( gap[dis[u]] == 0) break; dis[u] = mindis+1; gap[dis[u]]++; u = pre[u]; } return ret; } int main(void) { int n,f,d,t; char s[205]; while (scanf("%d%d%d",&n,&f,&d) == 3) { memset(head,-1,sizeof(head)); EN = 0; for(int i=1; i<=f; i++) { scanf("%d",&t); insert(0,i,t);//源点加边 } for(int i=1; i<=d; i++) { scanf("%d",&t); insert(f+2*n+i,f+2*n+d+1,t);//汇点加边 } for(int i=1; i<=n; i++) insert(f+i,f+n+i,1);//拆点 for(int i=1; i<=n; i++) { scanf("%s",s+1); for(int j=1; j<=f; j++) if (s[j] == 'Y') insert(j,f+i,1);//顾客与食物加边 } for(int i=1; i<=n; i++) { scanf("%s",s+1); for(int j=1; j<=d; j++) if (s[j] == 'Y') insert(f+n+i,f+2*n+j,1);//顾客与饮料加边 } printf("%d\n",sap(0,f+2*n+d+1,f+2*n+d+2)); } return 0; }