[luogu]P1402:酒店之王

原题链接

酒店之王

分析

先大致讲一下题意:
题目给定p道菜,q个房间和n个客人。
每个客人满意的条件当且仅当那个客人分配到的房间和菜都是自己喜欢的。

想都不想直接网络流,裸题。(但是因为没看清题意一开始疯狂30分)

模型:

  • 把每道菜,每个客人,每个房间看成点,有喜欢关系的就连有向边,容量为1。
  • 超级源向每一个菜,每个房间向超级汇连有向边,容量为1。
  • 客人拆点,入点向出点连一条容量为1的边。

这样子只要跑一边网络流求出最大流就行了。。(感觉没有紫题难度)

代码


#include <bits/stdc++.h>
using namespace std;
const int inf=1<<31-1;
queue <int> q;
int n,p,w,s=0,t;
int rm[109][109],tmp[109],d[529],flow,maxflow;
int head[529],ver[300009],next[300009],edge[300009],tot=1;
void add(int x,int y){
    ver[++tot]=y;edge[tot]=1;next[tot]=head[x];head[x]=tot;
    ver[++tot]=x;edge[tot]=0;next[tot]=head[y];head[y]=tot;
}
bool bfs();
int dinic(int x,int flow);
int main()
{
    int tt;
    scanf("%d%d%d",&n,&p,&w);
    t=p+2*n+w+1;
    for(int i=1;i<=p;i++)add(s,i);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=p;j++){
            scanf("%d",&tt);
            if(tt)add(j,i+p);
        }
    for(int i=1;i<=n;i++)add(i+p,i+p+n);
    for(int i=1;i<=n;i++){
        for(int j=1;j<=w;j++){
            scanf("%d",&tt);
            if(tt)add(p+n+i,p+2*n+j);
        }
    }
    for(int i=1;i<=w;i++)add(p+2*n+i,t);
    while(bfs())
        while(flow=dinic(s,inf))maxflow+=flow;
    cout<<maxflow<<endl;
    return 0;
}
bool bfs(){
    memset(d,0,sizeof(d));
    while(q.size())q.pop();
    q.push(s);d[s]=1;
    while(q.size()){
        int x=q.front();q.pop();
        for(int i=head[x];i;i=next[i]){
            if(!d[ver[i]] && edge[i]){
                d[ver[i]]=d[x]+1;
                q.push(ver[i]);
                if(ver[i]==t)return true;
            }
        }
    }
    return false;
}
int dinic(int x,int flow){
    if(x==t)return flow;
    int res=flow,k;
    for(int i=head[x];i&&res;i=next[i]){
        if(edge[i] && d[ver[i]]==d[x]+1){
            k=dinic(ver[i],min(flow,edge[i]));
            if(!k)d[ver[i]]=0;
            edge[i]-=k;
            edge[i^1]+=k;
            res-=k;
        }
    }
    return flow-res;
}

转载于:https://www.cnblogs.com/onglublog/p/9859755.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值