HDU6749 Mosquito 二分+网络流

题目描述

房间是个 n∗m 的网格,一共有 k 个窗户,都在上下左右四条边上。在第 0 时刻,每个窗户对应的格子上都会出现若干只蚊子。

蚊子每个时刻可以往上下左右移动一格或者呆在原地不动。

假设这些蚊子都足够聪明,请问最少花费多少时刻,使得所有格子上都有至少一只蚊子?

蚊子在第 0 时刻不能动。
1 ≤ m , n ≤ 1000 , 1 ≤ k ≤ 6 , 1 ≤ T ≤ 10 1\leq m,n \leq 1000 ,1\leq k \leq 6,1\leq T \leq 10 1m,n1000,1k6,1T10

分析

二分时刻,蚊子可以从窗户那到处走,所以可以流向时刻内就能到达的点
因为有100w个点,肉眼可知会TLE,我们想想优化
发现有一些点与窗户连边的情况是相同的,所以就可以合成一个点,流的流量是这些点的个数和
这样就可以AC了

代码

#include 

#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define dep(i,a,b) for(int i=(a);i>=(b);--i)
#define PB push_back
#define CL clear
//#define int long long
#define fi first
#define se second
using namespace std;
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
typedef pair<int,int> pii;
const int N = 100010;
const int inf = 1e9;
const int mod = 1e9+7;
inline int rd() {
  char ch = getchar(); int p = 0; int f = 1;
  while(ch<'0' || ch>'9'){if(ch=='-') f=-1; ch=getchar();}
  while(ch>='0' && ch<='9'){p=p*10+ch-'0'; ch=getchar();}
  return p*f;
}

struct node{int x,y,c,nex,other;}edge[N]; int len , fir[N]; int s,d;
void ins(int x,int y,int c) {
  len++; int k1=len; edge[len].x=x; edge[len].y=y; edge[len].c=c; edge[len].nex=fir[x]; fir[x]=len;
  len++; int k2=len; edge[len].x=y; edge[len].y=x; edge[len].c=0; edge[len].nex=fir[y]; fir[y]=len;
  edge[k1].other=k2; edge[k2].other=k1;
}

struct Dinic{
    int dep[N]; queue<int> q;
    bool bfs() {
      for(int i=s;i<=d;++i) dep[i] = 0;
        while(!q.empty()) q.pop(); q.push(s); dep[s] = 1;
        while(!q.empty()) {
          int x = q.front();
          for(int k=fir[x];k!=-1;k=edge[k].nex) {
            int y = edge[k].y;
                if(!dep[y] &&  edge[k].c) {
                dep[y] = dep[x] + 1; q.push(y);
                }
          }q.pop();
        }
        return dep[d] > 0;
    }
    int dfs(int x,int flow) {
      int delta = 0;
      if(x==d) return flow;
      for(int k=fir[x];k!=-1;k=edge[k].nex) {
        int y=edge[k].y;
        if(edge[k].c && flow > delta && dep[y] == dep[x]+1) {
          int minf = dfs(y,min(edge[k].c , flow-delta));
          edge[k].c-=minf; edge[edge[k].other].c+=minf;
          delta+=minf;
            }
        }if(delta == 0) dep[x] = 0;
        return delta;
    }
}dinic;

int n,m,k;
tuple<int,int,int>tp[N];

int cnt[N];

void build(int length) {
    s = 0; d =(1<<k)+k+1;
    for(int i=s;i<=d;i++) fir[i] = -1; len = 0;
    for(int i=0;i<(1<<k);i++) cnt[i] = 0;
  for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++) {
        int psta = 0;
      for(int p=1;p<=k;p++)
        if(abs(i-get<0>(tp[p])) + abs(j-get<1>(tp[p])) <= length)
          psta |= (1<<(p-1));
//      printf("%d %d %d\n",i,j,psta);
      cnt[psta] ++;
        }
    for(int p=0;p<(1<<k);p++) ins(s,p+1,cnt[p]);
    for(int p=0;p<(1<<k);p++) for(int q=1;q<=k;q++) if(p&(1<<(q-1)))
      ins(p+1,(1<<k)+q,inf);
    for(int p=1;p<=k;p++) ins((1<<k)+p,d,get<2>(tp[p]));
}

int check() {
    int ans = 0;
  while(dinic.bfs())
      ans+=dinic.dfs(s,inf);
    return ans == n*m; 
}

signed main() {
    int t = rd();
    while(t--) {
      n = rd(); m = rd(); k = rd();
      rep(i,1,k) {
        int x = rd(); int y = rd(); int d = rd();
            tp[i] = make_tuple(x,y,d);
        }
      int l = 0; int r = n*m; int ret = -1;
      while(l<=r) {
        int mid = (l+r)>>1;
        build(mid);
        if(check()) ret=mid,r=mid-1;
        else l=mid+1;
        }
        printf("%d\n",ret);
    }
    return 0;
}

你可能感兴趣的:(hdu,网络流,二分)