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

    传送门:https://www.luogu.org/problemnew/show/P1231

    这是一道很不错的网络流入门题,关键在于如何建图。

    首先,我们将练习册和源点连一条边权为1的边,然后若书 i 和练习册 j 可以配套,就将连一条从练习册 j 到书 i 边,当然边权还是1。同理,答案和书也是如此,最后再将答案和汇点连一条边权为1的边。

    但是这么写还是会有点问题,因为经过一本书的路径可能与很多条,书就被使用了多次,显然不符合题意。这时候我们可以将书 i 拆成书 i1 和 i2,i1 和练习册连边,i2 和答案连边,这样就保证没一本书之用过一次了。

    建好图后跑最大流就行了。

      1 #include<cstdio>
      2 #include<iostream>
      3 #include<algorithm>
      4 #include<cmath>
      5 #include<cstring>
      6 #include<cstdlib>
      7 #include<cctype>
      8 #include<stack>
      9 #include<queue>
     10 #include<vector>
     11 using namespace std;
     12 #define enter printf("
    ")
     13 #define space printf(" ")
     14 #define Mem(a) memset(a, 0, sizeof(a))
     15 typedef long long ll;
     16 typedef double db;
     17 const int INF = 0x3f3f3f3f;
     18 const db eps = 1e-8;
     19 const int maxn = 1e4 + 5;
     20 inline ll read()
     21 {
     22     ll ans = 0;
     23     char ch = getchar(), last = ' ';
     24     while(!isdigit(ch)) {last = ch; ch = getchar();}
     25     while(isdigit(ch))
     26     {
     27         ans = ans * 10 + ch - '0'; ch = getchar();
     28     }
     29     if(last == '-') ans = -ans;
     30     return ans;
     31 }
     32 inline void write(ll x)
     33 {
     34     if(x < 0) x = -x, putchar('-');
     35     if(x >= 10) write(x / 10);
     36     putchar(x % 10 + '0');
     37 }
     38 
     39 int t, n1, n2, n3;
     40 
     41 struct Edge
     42 {
     43     int from, to, cap, flow;
     44 };
     45 vector<Edge> edges;
     46 vector<int> G[maxn << 2];
     47 void addEdge(int from, int to)
     48 {
     49     edges.push_back((Edge){from, to, 1, 0});
     50     edges.push_back((Edge){to, from, 0, 0});
     51     int sz = edges.size();
     52     G[from].push_back(sz - 2);
     53     G[to].push_back(sz - 1);
     54 }
     55 
     56 int dis[maxn << 2];
     57 bool vis[maxn << 2];
     58 bool bfs()
     59 {
     60     Mem(vis);
     61     queue<int> q;
     62     q.push(0); vis[0] = 1;
     63     dis[0] = 0;
     64     while(!q.empty())
     65     {
     66         int now = q.front(); q.pop();
     67         for(int i = 0; i < (int)G[now].size(); ++i)
     68         {
     69             Edge& e = edges[G[now][i]];
     70             if(!vis[e.to] && e.cap > e.flow)
     71             {
     72                 vis[e.to] = 1;
     73                 dis[e.to] = dis[now] + 1;
     74                 q.push(e.to);
     75             }
     76         }
     77     }
     78     return vis[t];
     79 }
     80 int cur[maxn << 2];
     81 int dfs(int now, int a)
     82 {
     83     if(now == t || !a) return a;
     84     int flow = 0, f;
     85     for(int& i = cur[now]; i < (int)G[now].size(); ++i)
     86     {
     87         Edge& e = edges[G[now][i]];
     88         if(dis[e.to] == dis[now] + 1 && (f = dfs(e.to, min(a, e.cap - e.flow))) > 0)
     89         {
     90             e.flow += f;
     91             edges[G[now][i] ^ 1].flow -= f;        
     92             flow += f; a -= f;
     93             if(!a) break;    
     94         }
     95     }
     96     return flow;
     97 }
     98 
     99 int maxflow()
    100 {
    101     int flow = 0;
    102     while(bfs())
    103     {
    104         Mem(cur);
    105         flow += dfs(0, INF);
    106     }
    107     return flow;
    108 }
    109 
    110 //bool vis2[maxn];
    111 
    112 int main()
    113 {
    114     n1 = read(); n2 = read(); n3 = read();         
    115     t = (n1 << 1)+ n2 + n3 + 1;                //为了防止编号重复
    116 /*按注释掉的写法会WA掉,因为如果一本书多次输入,那么这个书
    117 就多次拆点,这一本书就可以使用多次了 */ 
    118 /*    int m = read();                            
    119     while(m--)
    120     {
    121         int x = read(), y = read();        
    122         addEdge(0, y + (n1 << 1));
    123         addEdge(y + (n1 << 1), x);
    124         addEdge(x, x + n1);
    125         vis2[x] = 1;
    126     }
    127     m = read();
    128     while(m--)
    129     {
    130         int x = read(), y = read();
    131         if(!vis2[x]) addEdge(x, x + n1), vis2[x] = 1;
    132         addEdge(x + n1, y + (n1 << 1) + n2);
    133         addEdge(y + (n1 << 1) + n2, t);
    134     }*/
    135     int m = read();
    136     while(m--)
    137     {
    138         int x = read(), y = read();
    139         addEdge(y + (n1 << 1), x);
    140     }
    141     m = read();
    142     while(m--)
    143     {
    144         int x = read(), y = read();
    145         addEdge(x + n1, y + (n1 << 1) + n2);
    146     }
    147     for(int i = 1; i <= n1; ++i) addEdge(i, i + n1);
    148     for(int i = 1; i <= n2; ++i) addEdge(0, i + (n1 << 1));
    149     for(int i = 1; i <= n3; ++i) addEdge(i + (n1 << 1) + n2, t);
    150     write(maxflow()); enter;
    151 }
  • 相关阅读:
    Active Directory如何用C#进行增加、删除、修改、查询用户与组织单位!
    showModalDialog和showModelessDialog的使用
    如何在GridView中使用DataFromatString
    GridView/DataGrid单元格不换行的问题
    要Gmail、Orkut邀请的请留下你的邮箱
    How to reset security settings back to the defaults
    ASP.NET 2.0 学习笔记 1: session 与 script 应用
    关闭主窗体而不退出主程序 以及如何获取操作系统的关闭、注销信息
    ASP.NET 2.0 学习笔记 2: 页面间传值
    Windows 系统常用设置方法与技巧
  • 原文地址:https://www.cnblogs.com/mrclr/p/9419034.html
Copyright © 2011-2022 走看看