• 洛谷P1402 酒店之王(网络流)


    ### 洛谷P1402 题目链接 ###

    题目大意:有 n 个人, p 间房间,q 种食物。每个人喜欢一些房间,一些食物,但每间房间、每种食物只能分配给一个人。问最大可以让多少个人满足(当且仅当分配到的房间和食物都是自己喜欢的)。

    分析:

    1、房间与食物只能被分配一次,被分配后不能再被利用。想到二分图匹配问题。

    2、再看题干发现,此题不能直接二分图匹配。因为还需要每个人本身也只能被利用一次。比如某个人喜欢的房间是 1 2 ,食物是 3 4 ,那么即便有 1 - 2 、3 - 4 两种匹配,但也只能满足这一个人,并不是满足了两个人的分配问题。

    3、综上,即要保证房间和食物的“流量”最大为1,还需要保证人的“流量”最大为 1 。故可以将房间连接于起点 S ,食物连接于终点 T ,容量为 1 。

    按样例来看,图应该为这样:

     

    这样保证了房间和食物只能被用一次,但这建图还是错的。。。因为不能保证 人(点3、点4)的流量最大是 1 。比如:

    加了这条红色的边后,点3 这个人的最大流量为 2 (从房间 1 和房间 2 流入。且流出于食物 5 和食物 6 ),与题干不符,所以需要把每个人拆成两点,然后中间连一条边,这样就可以限制人的流入与流出了。

    代码如下:

    #include<iostream>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #define maxn 408
    #define inf 0x3f3f3f3f
    using namespace std;
    typedef long long ll;
    queue<int> Q;
    int n,p,q,cnt,S,T;
    int head[maxn],cur[maxn],d[maxn];
    struct Edge{
        int to;
        int val;
        int next;    
    }edge[maxn*maxn];
    inline void add(int u,int v,int w){
        edge[++cnt].to=v;
        edge[cnt].val=w;
        edge[cnt].next=head[u];
        head[u]=cnt;
        return;
    }
    bool bfs(){
        while(!Q.empty()) Q.pop();
        memset(d,-1,sizeof(d));
        d[S]=0;
        Q.push(S);
        while(!Q.empty()){
            int u=Q.front();
            Q.pop();
            for(int i=head[u];~i;i=edge[i].next){
                int v=edge[i].to;
                if(d[v]==-1&&edge[i].val>0){
                    d[v]=d[u]+1;
                    Q.push(v);
                }
            }
        }
        return d[T]!=-1;
    }
    int dfs(int u,int flow){
        int nowflow=0;
        if(u==T) return flow;
        for(int i=cur[u];~i;i=edge[i].next){
            cur[u]=i;
            int v=edge[i].to;
            if(d[v]==d[u]+1&&edge[i].val>0){
                if(int k=dfs(v,min(flow-nowflow,edge[i].val))){
                    edge[i].val-=k;
                    edge[i^1].val+=k;
                    nowflow+=k;
                    if(nowflow==flow) break;
                }
            }
        }
        if(!nowflow) d[u]=-1;
        return nowflow;
    }
    int Dinic(){
        int ans=0;
        while(bfs()){
            for(int i=0;i<=T;i++) cur[i]=head[i];
            ans+=dfs(S,inf); 
        }
        return ans;
    }
    int main()
    {
        scanf("%d%d%d",&n,&p,&q);
        int A;
        cnt=-1;
        memset(head,-1,sizeof(head));
        S=0,T=2*n+p+q+1;
        for(int i=1;i<=p;i++) add(S,i,1),add(i,S,0);
        for(int i=1;i<=q;i++) add(p+2*n+i,T,1),add(T,p+2*n+i,0);
        for(int i=1;i<=n;i++){
            for(int j=1;j<=p;j++){
                scanf("%d",&A);
                if(A) add(j,p+i,1),add(p+i,j,0);
            }
            add(p+i,p+n+i,1),add(p+n+i,p+i,0);
        }
        for(int i=1;i<=n;i++){
            for(int j=1;j<=q;j++){
                scanf("%d",&A);
                if(A) add(p+n+i,p+2*n+j,1),add(p+2*n+j,p+n+i,0);
            }
        }
        printf("%d
    ",Dinic());
    }
  • 相关阅读:
    try? try! try do catch try 使用详解
    Swift Write to file 到电脑桌面
    NSLayoutConstraint 使用详解 VFL使用介绍
    automaticallyAdjustsScrollViewInsets 详解
    Swift 给UITableView 写extension 时 报错 does not conform to protocol 'UITableViewDataSource'
    OC Swift中检查代码行数
    Swift中 @objc 使用介绍
    SWift中 '?' must be followed by a call, member lookup, or subscript 错误解决方案
    Swift 中 insetBy(dx: CGFloat, dy: CGFloat) -> CGRect 用法详解
    求1000之内所有“完数”(注:C程序设计(第四版) 谭浩强/著 P141-9)
  • 原文地址:https://www.cnblogs.com/Absofuckinglutely/p/12213874.html
Copyright © 2020-2023  润新知