zoukankan      html  css  js  c++  java
  • 洛谷 P1231 教辅的组成

    题目背景

    滚粗了的(HansBug)在收拾旧语文书,然而他发现了什么奇妙的东西。

    题目描述

    蒟蒻(HansBug)在一本语文书里面发现了一本答案,然而他却明明记得这书应该还包含一份练习题。然而出现在他眼前的书多得数不胜数,其中有书,有答案,有练习册。已知一个完整的书册均应该包含且仅包含一本书、一本练习册和一份答案,然而现在全都乱做了一团。许多书上面的字迹都已经模糊了,然而(HansBug)还是可以大致判断这是一本书还是练习册或答案,并且能够大致知道一本书和答案以及一本书和练习册的对应关系(即仅仅知道某书和某答案、某书和某练习册有可能相对应,除此以外的均不可能对应)。既然如此,(HansBug)想知道在这样的情况下,最多可能同时组合成多少个完整的书册。

    输入输出格式

    输入格式:

    第一行包含三个正整数(N1、N2、N3),分别表示书的个数、练习册的个数和答案的个数。

    第二行包含一个正整数(M1),表示书和练习册可能的对应关系个数。

    接下来M1行每行包含两个正整数(x、y),表示第(x)本书和第(y)本练习册可能对应。((1<=x<=N1,1<=y<=N2))

    (M1+3)行包含一个正整数(M2),表述书和答案可能的对应关系个数。

    接下来(M2)行每行包含两个正整数(x、y),表示第(x)本书和第(y)本答案可能对应。((1<=x<=N1,1<=y<=N3))

    输出格式:

    输出包含一个正整数,表示最多可能组成完整书册的数目。

    输入输出样例

    输入样例#1:

    5 3 4
    5
    4 3
    2 2
    5 2
    5 1
    5 3
    5
    1 3
    3 1
    2 2
    3 3
    4 3
    

    输出样例#1:

    2
    

    说明

    样例说明:

    如题,(N1=5,N2=3,N3=4),表示书有(5)本、练习册有(3)本、答案有(4)本。

    (M1=5),表示书和练习册共有(5)个可能的对应关系,分别为:书(4)和练习册(3)、书(2)和练习册(2)、书(5)和练习册(2)、书(5)和练习册(1)以及书(5)和练习册3。

    (M2=5),表示数和答案共有(5)个可能的对应关系,分别为:书(1)和答案(3)、书(3)和答案(1)、书(2)和答案(2)、书(3)和答案(3)以及书(4)和答案(3)

    所以,以上情况的话最多可以同时配成两个书册,分别为:书(2)+练习册(2)+答案(2)、书(4)+练习册(3)+答案(3)

    数据规模:

    对于数据点(1, 2, 3,M1,M2<= 20)

    对于数据点(4)~(10)(M1,M2 <= 20000)

    思路:开始尝试用二分图做这道题的,理论上应该是可以的,但是却WA了,就是建两个二分图,如果这本书与同一本答案和练习都可以匹配,那么最终就可以配。所以就还是用了网络流还做这道题,要涉及到拆点操作,构图思想大致是:源点——练习——书——书的分身(等等再说)——答案——汇点。为什么有两个书呢?因为我们要将书分别连向练习和答案,因此,也必须要用两个书,就复制一遍就好了,建边的时间容量为1,反向边为0。其实就是把分给拆点,目的是限制流量。

    代码:

    #include<cstdio>
    #include<cctype>
    #include<cstring>
    #include<queue>
    #define maxn 1000007
    #define inf 0x3f3f3f3f
    using namespace std;
    int n1,n2,n3,m1,m2,S,T,head[maxn],num=1,d[maxn];
    inline int qread() {
      char c=getchar();int num=0,f=1;
      for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
      for(;isdigit(c);c=getchar()) num=num*10+c-'0';
      return num*f;
    }
    struct node {
      int v,f,nxt;
    }e[1000007];
    inline void ct(int u, int v, int f) {
      e[++num]=node{v,f,head[u]};
      head[u]=num;
    }
    inline bool bfs() {
      memset(d,-1,sizeof(d));
      queue<int>q;
      q.push(S),d[S]=0;
      while(!q.empty()) {
        int u=q.front();
        q.pop();
        for(int i=head[u];i;i=e[i].nxt) {
          int v=e[i].v;
          if(e[i].f&&d[v]==-1) {
            d[v]=d[u]+1;
            q.push(v);  
          }
        }
      }
      return d[T]!=-1;
    }
    int dfs(int u, int f) {
      if(u==T) return f;
      int rest=0;
      for(int i=head[u];i;i=e[i].nxt) {
        int v=e[i].v;
        if(d[v]==d[u]+1&&e[i].f) {
          int t=dfs(v,min(e[i].f,f-rest));
          if(!t) d[v]=0;
          e[i].f-=t;
          e[i^1].f+=t;
          rest+=t;
          if(f==rest) return rest;
        }
      }
      return rest;
    }
    inline int dinic() {
      int ans=0;
      while(bfs()) ans+=dfs(S,inf);
      return ans;
    }
    int main() {
      n1=qread(),n2=qread(),n3=qread();
      S=1,T=n1*2+n2+n3+2;
      m1=qread();
      for(int i=1,u,v;i<=m1;++i) {
        u=qread(),v=qread();
        ct(v+1,u+n2+1,1);
        ct(u+n2+1,v+1,0);
      }
      for(int i=n2+2;i<=n2+n1+1;++i) ct(i,i+n1,1),ct(i+n1,i,0);
      m2=qread();
      for(int i=1,u,v;i<=m2;++i) {
        u=qread(),v=qread();
        ct(n2+u+n1+1,n2+2*n1+v+1,1);
        ct(n2+2*n1+v+1,n2+u+n1+1,0);
      }
      for(int i=2;i<=n2+1;++i) ct(S,i,1),ct(i,S,0);
      for(int i=n2+n1*2+2;i<=T-1;++i) ct(i,T,1),ct(T,i,0);
      printf("%d
    ",dinic());
      return 0;
    }
    
  • 相关阅读:
    C++ Stream(串流)迭代器
    C++ deque const_iterator const_reverse_iterator运用实例
    C++ iter_swap()运用实例
    C++ distance()处理迭代器之间的距离
    数据库历险记(二) | Redis 和 Mecached 到底哪个好?
    数据库历险记(一) | MySQL这么好,为什么还有人用Oracle?
    面对海量请求,缓存设计还应该考虑哪些问题?
    90后小伙利用支付宝漏洞被抓, 我为什么拍手叫好?
    从抖音关闭评论,看服务治理的重要性
    优秀程序员具备的高效习惯,你具备吗?
  • 原文地址:https://www.cnblogs.com/grcyh/p/10804279.html
Copyright © 2011-2022 走看看