「八省联考2018」 劈配

Description

由于题面太长就直接挂链接了

Solution

考虑网络流,我们将前个的最优匹配的图给存下来,对于第一问,直接暴力枚举他是第几志愿的,然后连边跑一下,看是否有增广,这样就做完了第一问

对于第二问,如果他的最优志愿小于等于,那么答案就是,否则考虑二分他前进的排名,然后将的志愿全部连上边,再在上面的网络流图中判断一下是否增广即可

Code

 //Created Time:2020年06月07日 星期日 16时04分54秒
 #include <queue>
 #include <vector>
 #include <cstdio>
 #include <cstring>
 #include <iostream>
 #include <algorithm>
 #define N 202
 #define vec vector<int>
 #define oo 999999999
 
 using namespace std;
 
 int n, m, S, T;
 int b[N], res[N], dis[N << 1], tmp[N << 1];
 
 vec p[N][N];
 
 struct edge{
  int to, nxt, f;
 };
 
 struct graph{
  int cnt;
  int fir[N << 1], cur[N << 1];
  edge e[N * 50];
 
  void operator = (graph &x){
  cnt = x.cnt;
  memcpy(fir, x.fir, (T + 1) << 2);
  for(int i = 0; i <= cnt; ++i)
  e[i] = x.e[i];
  return ;
  }
 
 
  void add(int u, int v, int f){
  e[++cnt] = (edge){v, fir[u], f}; fir[u] = cnt;
  e[++cnt] = (edge){u, fir[v], 0}; fir[v] = cnt;
  return ;
  }
 
  bool bfs(){
  queue<int> Q;
  memset(dis, -1, (T + 1) << 2);
  dis[S] = 0; Q.push(S);
  while(!Q.empty()){
  int u = Q.front(); Q.pop();
  for(int i = fir[u]; ~i; i = e[i].nxt){
  int v = e[i].to;
  if(dis[v] == -1 && e[i].f){
  dis[v] = dis[u] + 1;
  Q.push(v);
  }
  }
  }
  return dis[T] != -1;
  }
 
  int dfs(int u, int flow){
  if(u == T) return flow;
  int sum = 0;
  for(int &i = cur[u]; ~i; i = e[i].nxt){
  int v = e[i].to, f = e[i].f;
  if(dis[v] != dis[u] + 1 || !f) continue;
  int d = dfs(v, min(f, flow));
  if(!d) continue;
  e[i].f -= d; e[i ^ 1].f += d;
  sum += d; flow -= d;
  if(!flow) break;
  }
  if(!sum) dis[u] = -1;
  return sum;
  }
 
  bool check(){
  if(!bfs()) return false;
  memcpy(cur, fir, (T + 1) << 2);
 int d = dfs(S, 1); 
return d; 

}g[N]; 
​ 
void work(); 
​ 
int main(){ 
#ifndef ONLINE_JUDGE 
   freopen("a.in", "r", stdin); 
   freopen("a.out", "w", stdout); 
#endif 
int T, C; cin >> T >> C; 
while(T--) work(); 
return 0; 

​ 
void work(){ 
scanf("%d%d", &n, &m); 
for(int i = 1; i <= m; ++i) 
scanf("%d", b + i); 
for(int i = 1; i <= n; ++i) 
for(int j = 1; j <= m; ++j){ 
int x; scanf("%d", &x); 
if(!x) continue; 
p[i][x].push_back(j); 

g[0].cnt = -1; S = 0; T = n + m + 1; 
memset(g[0].fir, -1, (T + 1) << 2); 
for(int i = 1; i <= m; ++i)  
g[0].add(i + n, T, b[i]); 
for(int i = 1; i <= n; ++i){ 
g[i] = g[i - 1]; g[i].add(S, i, 1); 
res[i] = 1; 
for(int &j = res[i]; j <= m; ++j){ 
if(p[i][j].empty()) continue; 
int pre = g[i].cnt; 
memcpy(tmp, g[i].fir, (T + 1) << 2); 
for(auto v : p[i][j]) 
g[i].add(i, v + n, 1); 
if(g[i].check()) break; 
memcpy(g[i].fir, tmp, (T + 1) << 2); 
g[i].cnt = pre; 

printf("%d ", res[i]); 

puts(""); 
for(int i = 1; i <= n; ++i){ 
int s; scanf("%d", &s); 
if(s >= res[i]){ 
putchar('0'); putchar(' '); 
continue; 

int l = 1, r = i - 1, ans = 0; 
while(l <= r){ 
int mid = (l + r) >> 1; 
graph P; P = g[mid - 1]; 
P.add(S, i, 1); 
for(int j = 1; j <= s; ++j) 
for(auto v : p[i][j]) 
P.add(i, v + n, 1); 
if(P.check()) ans = mid, l = mid + 1; 
else r = mid - 1; 

printf("%d ", i - ans); 

puts(""); 
for(int i = 1; i <= n; ++i) 
for(int j = 1; j <= m; ++j) 
p[i][j].clear(); 
return ; 
}



原文地址:https://www.cnblogs.com/roal-l/p/13085940.html