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("\n")
 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 }

 

上一篇:sizeof和strlen的区别和联系总结


下一篇:什么是BFC