SPOJ AMR12A The Black Riders(二分+二分匹配)

来源:互联网 发布:mac换电池 编辑:程序博客网 时间:2024/05/16 07:54

有n个人,m个洞。每个洞能容纳一个人,每个人到每个洞需要花费一些时间。每个人到达一个洞后可以花C的时间来挖洞,这样该洞的容量就变成2了。求能使至少K个人进洞的最短时间。

还是将求极值问题转化为判定问题。二分枚举时间,能否在time的时间内让至少K个人进洞?求进洞人数当然用二分匹配做。g[i][j]为第i个人到第j个洞的时间。如果g[i][j] <= time,那么由i向j连边。挖洞的情况呢?如果g[i][j] + C <= time的话,由i向j和j+m分别连边,这样就能保证在时间够的情况下改变洞的容量了。

#include<algorithm>#include<iostream>#include<cstring>#include<fstream>#include<sstream>#include<cstdlib>#include<vector>#include<string>#include<cstdio>#include<bitset>#include<queue>#include<stack>#include<cmath>#include<map>#include<set>#define FF(i, a, b) for(int i=a; i<b; i++)#define FD(i, a, b) for(int i=a; i>=b; i--)#define REP(i, n) for(int i=0; i<n; i++)#define CLR(a, b) memset(a, b, sizeof(a))#define debug puts("**debug**")#define LL long long#define PB push_back#define MP make_pairusing namespace std;const int maxn = 222;int n, m, K, C, g[maxn][maxn];struct BPM{  int n, m;               // 左右顶点个数  int G[maxn][maxn];      // 邻接表  int left[maxn];         // left[i]为右边第i个点的匹配点编号,-1表示不存在  bool T[maxn];           // T[i]为右边第i个点是否已标记  void init(int n, int m) {    this->n = n;    this->m = m;    memset(G, 0, sizeof(G));  }  inline void add(int u, int v)  {      G[u][v] = 1;  }  bool match(int u){    for(int v = 0; v < m; v++) if(G[u][v] && !T[v]) {      T[v] = true;      if (left[v] == -1 || match(left[v])){        left[v] = u;        return true;      }    }    return false;  }  // 求最大匹配  int solve() {    memset(left, -1, sizeof(left));    int ans = 0;    for(int u = 0; u < n; u++) { // 从左边结点u开始增广      memset(T, 0, sizeof(T));      if(match(u)) ans++;    }    return ans;  }}solver;bool ok(int time){    solver.init(n, m*2);    REP(i, n) REP(j, m)    {        if(g[i][j] <= time) solver.add(i, j);        if(g[i][j] + C <= time) solver.add(i, j+m);    }    return solver.solve() >= K;}int main(){    int T; scanf("%d", &T);    while(T--)    {        int L = 0, R = -1, M, ans;        scanf("%d%d%d%d", &n, &m, &K, &C);        REP(i, n) REP(j, m)        {            scanf("%d", &g[i][j]);            R = max(R, g[i][j]);        }        while(L <= R)        {            M = (L + R) >> 1;            if(ok(M)) ans = M, R = M - 1;            else L = M + 1;        }        printf("%d\n", ans);    }    return 0;}