• 「八省联考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 ; 
    }



  • 相关阅读:
    计算任意两个日期的间隔天数
    题目标题: 排它平方数
    历届试题 剪格子
    历届试题 翻硬币
    C语言中%d,%o,%f,%e,%x的意义
    历届试题 买不到的数目
    九度 OJ1008 hdu 3790
    南洋理工 OJ 115 城市平乱 dijstra算法
    蓝桥杯 错误票据 原创代码+思路
    历届试题 连号区间数
  • 原文地址:https://www.cnblogs.com/roal-l/p/13085940.html
Copyright © 2020-2023  润新知