luogu P1402 酒店之王
题目

解法
看到这道题的时候,就想到了罗老师讲课的时候讲到的网络流建模的经典题:Dining。结果一翻题解发现全是二分图匹配,吓得我赶紧又学习了一下二分图。
我们发现一个人要分别与一个房间和一道菜一一对应。就是一个最大匹配嘛。
于是跑两张二分图就行了,只有两边都有增广路的时候才算匹配成功。否则我们要退边。(不然会WA)。
代码
二分图版。
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <algorithm> #include <cctype> #include <vector> #define INF 2139062143 #define MAX 0x7ffffffffffffff #define del(a,b) memset(a,b,sizeof(a)) using namespace std; typedef long long ll; template<typename T> inline void read(T&x) { x=0;T k=1;char c=getchar(); while(!isdigit(c)){if(c=='-')k=-1;c=getchar();} while(isdigit(c)){x=x*10+c-'0';c=getchar();}x*=k; } const int maxn=105; int bian[2][maxn][maxn]; int find_[2][maxn]; int temp[2][maxn]; bool vis[2][maxn]; int n,num[2]; bool _find(int pos,int id) { for(int i=1;i<=num[id];i++) { if(bian[id][pos][i]&&!vis[id][i]) { vis[id][i]=1; if(!find_[id][i]||_find(find_[id][i],id)) { find_[id][i]=pos; return 1; } } } return 0; } int main() { read(n),read(num[0]),read(num[1]); for(int i=1;i<=n;i++) for(int j=1;j<=num[0];j++) read(bian[0][i][j]); for(int i=1;i<=n;i++) for(int j=1;j<=num[1];j++) read(bian[1][i][j]); int ans=0; for(int i=1;i<=n;i++) { for(int i=1;i<=num[0];i++) temp[0][i]=find_[0][i]; for(int i=1;i<=num[1];i++) temp[1][i]=find_[1][i]; del(vis,0); if(_find(i,0)&&_find(i,1)) ++ans; else{ for(int i=1;i<=num[0];i++) find_[0][i]=temp[0][i]; for(int i=1;i<=num[1];i++) find_[1][i]=temp[1][i]; } } printf("%d\n",ans); return 0; }
网络流版。
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <algorithm> #include <cctype> #include <vector> #include <queue> #define INF 2139062143 #define MAX 0x7ffffffffffffff #define del(a,b) memset(a,b,sizeof(a)) using namespace std; typedef long long ll; template<typename T> inline void read(T&x) { x=0;T k=1;char c=getchar(); while(!isdigit(c)){if(c=='-')k=-1;c=getchar();} while(isdigit(c)){x=x*10+c-'0';c=getchar();}x*=k; } const int maxn=405; struct Dinic{ struct Edge{ int from,to,cap,flow; }; int n,m,s,t; vector<Edge> edges; vector<int> G[maxn]; bool vis[maxn]; int d[maxn]; int cur[maxn]; inline void add_edge(int from,int to,int cap){ edges.push_back( (Edge){from,to,cap,0} ); edges.push_back( (Edge){to,from,0,0} ); m=edges.size(); G[from].push_back(m-2); G[to].push_back(m-1); } inline bool bfs(){ del(vis,0); queue<int> Q; Q.push(s); d[s]=0; vis[s]=1; while(!Q.empty()){ int x=Q.front();Q.pop(); for(int i=0;i<G[x].size();i++){ Edge &e=edges[G[x][i]]; if(!vis[e.to]&&e.cap>e.flow){ vis[e.to]=1; d[e.to]=d[x]+1; Q.push(e.to); } } } return vis[t]; } inline int dfs(int x,int a){ if(x==t || a==0) return a; int flow=0,f; for(int &i=cur[x];i<G[x].size();i++){ Edge&e =edges[G[x][i]]; if(d[x]+1 == d[e.to] && (f = dfs(e.to , min(a , e.cap-e.flow))) ){ e.flow+=f; edges[G[x][i]^1].flow-=f; flow+=f; a-=f; if(!a) break; } } return flow; } inline int Maxflow(int s,int t){ this->s=s;this->t=t; int flow=0; while(bfs()){ del(cur,0); flow+=dfs(s,INF); } return flow; } }dinic; int n,p,q; int s,t; int main() { read(n),read(p),read(q); for(int i=1,x;i<=n;i++) { for(int j=1;j<=p;j++) { read(x); if(x) dinic.add_edge(j,i+p,1); } } for(int i=1,x;i<=n;i++) { for(int j=1;j<=q;j++) { read(x); if(x) dinic.add_edge(i+n+p,j+p+2*n,1); } } for(int i=p+1;i<=p+n;i++) dinic.add_edge(i,i+n,1); s=0,t=p+2*n+q+1; for(int i=1;i<=p;i++) dinic.add_edge(s,i,1); for(int i=p+2*n+1;i<=p+2*n+q;i++) dinic.add_edge(i,t,1); printf("%d\n",dinic.Maxflow(s,t)); return 0; }
注:
这道题成功的告诉我们,当你在NOIP中碰到了类似网络流的题时,千万不能慌张,因为它一定是一道二分图的题。

浙公网安备 33010602011771号