题目描述 Description
XX酒店的老板想成为酒店之王,本着这种希望,第一步要将酒店变得人性化。由于很多来住店的旅客有自己喜好的房间色调、阳光等,也有自己所爱的菜,但是该酒店只有p间房间,一天只有固定的q道不同的菜。
有一天来了n个客人,每个客人说出了自己喜欢哪些房间,喜欢哪道菜。但是很不幸,可能做不到让所有顾客满意(满意的条件是住进喜欢的房间,吃到喜欢的菜)。
这里要怎么分配,能使最多顾客满意呢?
输入输出格式 Input/output
输入格式:
第一行给出三个正整数表示n,p,q(<=100)。
之后n行,每行p个数包含0或1,第i个数表示喜不喜欢第i个房间(1表示喜欢,0表示不喜欢)。
之后n行,每行q个数,表示喜不喜欢第i道菜。
输出格式:
最大的顾客满意数。
输入样例:
2 2 2
1 0
1 0
1 1
1 1
输出样例:
1
题解:裸的网络流。别忘了把一个人拆成两个人。
#include<iostream> #include<cstdio> using namespace std; const int INF=~0U>>2; int s=0,t; int n,p,q; int map[405][405]; int dis[405],sumd[405],now[405]; int fanhui[405],pre[405]; int ans=0; void init() { scanf("%d%d%d",&n,&p,&q); t=2*n+p+q+1; for (int i=1; i<=p; i++) map[0][i]=1; for (int i=1; i<=n; i++) map[i+p][i+p+n]=1; for (int i=1; i<=q; i++) map[i+p+n+n][t]=1; for (int i=1; i<=n; i++) for (int j=1; j<=p; j++) cin >> map[j][i+p]; for (int i=1; i<=n; i++) for(int j=1; j<=q; j++) cin >> map[i+p+n][j+p+n+n]; } void sap() { sumd[0]=t+1;//sumd[i]表示编号为i的点的数量 int i=s; now[i]=0;//now[i]表示i连接的点 int flow=INF; while (dis[s]<t)//dis是标号 { fanhui[i]=flow;//这是非递归的写法,fanhui数组用于递归 bool flag=false; for (int j=0; j<=t; j++) if (map[i][j]>0 && dis[i]==dis[j]+1) { flag=true; if (map[i][j]<flow) flow=map[i][j]; now[i]=j; pre[j]=i; i=j; if (i==t) { ans++;//增广成功 while (pre[i]!=0) { int k=pre[i]; map[k][i]-=flow; map[i][k]+=flow;//流量网络的处理 i=k; } map[s][i]-=flow; map[i][s]+=flow; i=s; } break;//一次只找一条增广路 } if (flag) continue; int kk=INF;//kk保存距离i点最小的标号 for (int j=0; j<=t; j++) if (dis[j]<kk && map[i][j]>0) kk=dis[j]; sumd[dis[i]]--; if (sumd[dis[i]]==0) break;//如果标号出现断层也就不可能找到增广路 dis[i]=kk+1; sumd[dis[i]]++; flow=fanhui[i]; if (i!=0) i=pre[i]; } cout << ans; return; } int main() { init(); sap(); return 0; }