「网络流24题」圆桌问题
传送门:>Here<
题意:M个单位每个单位有a[i]个人。现在他们要一起聚餐。共有N张餐桌,每张餐桌容量为c[i],要求每个单位内部的人不能做同一张餐桌。输出一种分配方案(不行则输出0)
思路分析
一眼题解都没瞟就A了 说明最大流还是没有白学 233
一看这题容量就不能全是1了,肯定跟餐桌容量与单位人数有关。不妨先从源点连边到每个单位,容量就是这个单位的人数。每个单位连容量为1的边到各个餐桌。各个餐桌再连边到汇点,容量为餐桌容量。在这里,餐桌到汇点的容量用来约束每个餐桌的人数上限,而中间的容量为1的边则约束每个单位到每个餐桌最多一个人。源点到各个单位的容量就约束了每个单位的人数了。因此问题就迎刃而解。
因此每一条流量为1的流代表着一个人,从一个单位发散出去的流就是这个单位的人的分配了。判断是否有解也就是判断最大流是否等于人数之和
Code
none!
/*By DennyQi*/ #include <cstdio> #include <queue> #include <cstring> #include <algorithm> #define r read() #define Max(a,b) (((a)>(b)) ? (a) : (b)) #define Min(a,b) (((a)<(b)) ? (a) : (b)) using namespace std; typedef long long ll; const int MAXN = 100010; const int MAXM = 270010; const int INF = 1061109567; inline int read(){ int x = 0; int w = 1; register int c = getchar(); while(c ^ '-' && (c < '0' || c > '9')) c = getchar(); if(c == '-') w = -1, c = getchar(); while(c >= '0' && c <= '9') x = (x << 3) +(x << 1) + c - '0', c = getchar(); return x * w; } int N,M,S,T,x,ans,tot_num; int first[MAXM],nxt[MAXM],to[MAXM],cap[MAXM],flow[MAXM],num_edge=-1; int level[MAXN],cur[MAXN]; queue <int> q; inline void add(int u, int v, int c, int f){ to[++num_edge] = v; cap[num_edge] = c; flow[num_edge] = f; nxt[num_edge] = first[u]; first[u] = num_edge; } inline bool BFS(){ memset(level, 0, sizeof(level)); while(!q.empty()) q.pop(); q.push(S); level[S] = 1; int u,v; while(!q.empty()){ u = q.front(); q.pop(); for(int i = first[u]; i != -1; i = nxt[i]){ v = to[i]; if(!level[v] && cap[i]-flow[i] > 0){ level[v] = level[u] + 1; q.push(v); } } } return level[T]!=0; } int DFS(int u, int a){ if(u == T || a == 0) return a; int ans = 0, _f, v; for(int& i = cur[u]; i != -1; i = nxt[i]){ v = to[i]; if(level[u]+1 == level[v] && cap[i]-flow[i] > 0){ _f = DFS(v, Min(a, cap[i]-flow[i])); ans += _f, a -= _f; flow[i] += _f, flow[i^1] -= _f; if(a == 0) break; } } return ans; } inline void Dinic(){ ans = 0; while(BFS()){ for(int i = 1; i <= T; ++i) cur[i] = first[i]; ans += DFS(S, INF); } } int main(){ // freopen(".in","r",stdin); M=r,N=r; memset(first,-1,sizeof(first)); S = N+M+2, T = N+M+3; for(int i = 1; i <= M; ++i){ x=r; tot_num += x; add(S, i, x, 0); add(i, S, 0, 0); for(int j = 1; j <= N; ++j){ add(i, j+M, 1, 0); add(j+M, i, 0, 0); } } for(int i = 1; i <= N; ++i){ x=r; add(i+M, T, x, 0); add(T, i+M, 0, 0); } Dinic(); if(ans != tot_num){ printf("0\n"); return 0; } printf("1\n"); for(int i = 1; i <= M; ++i){ for(int j = first[i]; j != -1; j = nxt[j]){ if(cap[j]-flow[j] == 0 && cap[j] == 1){ printf("%d ", to[j]-M); } } printf("\n"); } return 0; }