1. 程式人生 > >luoguP1402 酒店之王

luoguP1402 酒店之王

har 之間 ace 情況 () ron print 酒店 一位

為了練dinic優化,再寫一道網絡流

原題鏈接:

https://www.luogu.org/problemnew/show/P1402

寫了很多非常辣雞的代碼還覺得挺對的我。。。

題意簡述:有n個顧客,m道菜,q個房間,顧客滿意的條件是能吃到自己喜歡的菜,住自己滿意的房間,求最多能讓多少顧客滿意。

首先建邊,源點連向所有的菜,菜向喜歡這道菜的顧客連一條邊,顧客向他喜歡的房間連一條邊,跑最大流即可。

然而這是錯的。

為什麽?假設有這個情況,一位顧客同時喜歡多個房間,但是很顯然,他最多只能住一個房間,也就是流過這個顧客點的流量最大為1,這就是點流量的題了,解決方法就是把顧客拆開,一個只吃菜,一個只住房間(emmm...),然後在這個兩個點之間連一條容量為1的邊,這樣再跑最大流就是對的了。

點:

房間  1--m
人1   m+1--m+n
人2   m+n+1--m+n<<1
菜    m+n<<1+1--m+n<<1+q

#include<cstdio>
#include<queue>
#include<cstring>
#include<iostream>
using namespace std;
const int inf=2147483647;
void read(int &y)
{
    y=0;char x=getchar();
    while(x<
0||x>9) x=getchar(); while(x>=0&&x<=9) { y=y*10+x-0; x=getchar(); } } struct edge { int u,v,w; }e[100005]; int n,m,q; int s,t=505,cnt=1; int head[1005],dis[1005]; int min(int a,int b) { return a<b?a:b; } void add(int u,int v) { e[++cnt].u=head[u];e[cnt].v=v; e[cnt].w
=1;head[u]=cnt; e[++cnt].u=head[v];e[cnt].v=u; e[cnt].w=0;head[v]=cnt; } int dfs(int x,int f) { if(x==t) return f; int d,tmp=0; for(int i=head[x];i!=-1;i=e[i].u) { int nxt=e[i].v; if(dis[nxt]==dis[x]+1&&e[i].w>0) { d=dfs(nxt,min(f-tmp,e[i].w)); if(d==0) continue; e[i].w-=d; e[i^1].w+=d; tmp+=d; if(tmp==f) return tmp; } } if(!tmp) dis[x]=0; return tmp; } int bfs() { memset(dis,0,sizeof(dis)); queue<int>q; q.push(0);dis[0]=1; while(!q.empty()) { int tmp=q.front();q.pop(); for(int i=head[tmp];i!=-1;i=e[i].u) { int p=e[i].v; if(dis[p]||e[i].w<=0) continue; dis[p]=dis[tmp]+1; q.push(p); } } return dis[t]; } int dinic() { int re=0; while(bfs()) re+=dfs(0,inf); return re; } int main() { memset(head,-1,sizeof(head)); read(n);read(m);read(q); int x; for(int i=1;i<=m;i++) add(s,i); for(int i=1;i<=n;i++) add(m+i,m+n+i); for(int i=1;i<=q;i++) add(m+(n<<1)+i,t); for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { read(x); if(x==1) add(j,m+i); } } for(int i=1;i<=n;i++) { for(int j=1;j<=q;j++) { read(x); if(x==1) add(m+n+i,m+(n<<1)+j); } } printf("%d",dinic()); return 0; }

luoguP1402 酒店之王