【百度之星】2020初赛第一场1007 Mosquito (hdu6749) | 最大流、状态压缩、优化建图

【百度之星】2020初赛第一场1007 Mosquito (hdu6749) | 最大流、状态压缩、优化建图_第1张图片

题目大意:

中文题意

题目思路:

 首先可以肯定,如果\sum{z_i} < n*m,肯定-1

否则的话一定可以跑满所有点。

既然一定可以跑满所有点,那么剩下的即为检验问题。

可以发现当前的t满足二分的单调性,如果最小的t可以,那么t+1一定也可以。

所以说就可以二分当前的时间t,看t是否存在一种合法的分配方案。

考虑到一个性质,一个蚊子只能占据一个,所以和网络流相关。

接下来就变成了,使用网络流检验当前t是否合法

如何建图呢?

我们可以这么想:首先S点对k个窗户的流量为a[k],之后每个窗户可以对当前t时间内可到达的点都有1的流量,之后每个点向汇点S都有1的流量,之后只需要检验最大流是否为n*m即可

但是这样建图的话 任何一种最大流的算法也没有合理的复杂度去处理这个问题,所以考虑一下建图。

如何优化建图呢?

考虑其实某些点是可以合并的,第k个窗户在t时间内可以到达的点集就完全可以合并,流量为a[k](设为当前最大值即可)。

之后状态压缩一下,假设x第k位为1,表示第k个窗户可以到达该点(状态),也就是说这个状态里的所有点第k个窗户都可以到达,所以此时只需要从k个窗户 向 x状态输送 点集大小的流量即可。

这样就完成了缩点,把k个窗户以及所有状态看为点,建图之后,跑一下最大流即可。

Code:

/*** keep hungry and calm CoolGuang!***/
#pragma GCC optimize(2)
#include 
#define debug(x) cout<<#x<<":"< pp;
const ll INF=1e17;
const int Maxn=2e7+10;
const int maxn =2e3+10;
const int mod=998244353;
const int Mod = 1e9+7;
///const double eps=1e-10;
inline bool read(ll &num)
{char in;bool IsN=false;
    in=getchar();if(in==EOF) return false;while(in!='-'&&(in<'0'||in>'9')) in=getchar();if(in=='-'){ IsN=true;num=0;}else num=in-'0';while(in=getchar(),in>='0'&&in<='9'){num*=10,num+=in-'0';}if(IsN) num=-num;return true;}
ll n,m,p,S,T;

///Net Flow
ll cnt = 2;
int head[maxn],cur[maxn],gap[maxn],d[maxn];///当前弧优化 、 断层
ll flow[maxn];
int MAX;
struct node{
    int e,next;
    ll w;
}edge[maxn];
void _inint_(){
    memset(head,0,sizeof(head));
    memchr(cur,0,sizeof(cur));
    memset(gap,0,sizeof(gap));
    cnt = 2;
}
void addedge(int u,int v,ll w){
    edge[cnt] = node{v,head[u],w};
    head[u] = cnt++;
}
void bfs(){
    memset(d,0,sizeof(d));
    queueq;q.push(T);d[T] = 1;
    while(!q.empty()){
        int u = q.front();q.pop();
        for(int i=head[u];i;i=edge[i].next){
            int e = edge[i].e;
            if(d[e]) continue;
            d[e] = d[u]+1;
            ++gap[d[e]];
            q.push(e);
        }
    }
    for(int i=0;i<=MAX+p+2;i++) cur[i] = head[i];///now
}
ll dfs(int u,ll flow){///
    if(u == T) return flow;
    ll delta = 0,temp;
    for(int i=cur[u];i;i=edge[i].next){
        int e = edge[i].e;
        if(d[u] != d[e]+1||edge[i].w<=0) continue;
        temp = dfs(e,min(flow-delta,edge[i].w));
        if(temp<=0) continue;
        edge[i].w -= temp;
        edge[i^1].w += temp;
        delta += temp;
        if(delta == flow) return flow;
    }
    ///否则出现断层
    if(--gap[d[u]]==0) d[S] = T+1;
    ++gap[++d[u]];
    cur[u] = head[u];
    return delta;
}
ll ISAP(){
    ll maxflow = 0,delta = 0;
    bfs();
    while(d[S] <= T) maxflow += dfs(S,INF);
    return maxflow;
}
///Net Flow

struct Point{
    int x,y,a;
}q[15];;
int ct[120];
int judge(int x){
    memset(ct,0,sizeof(ct));
    for(int i=1;i<=n;i++){
        for(int k=1;k<=m;k++){
            ll temp = 0;
            for(int j=1;j<=p;j++){
                int dis = abs(q[j].x-i)+abs(q[j].y-k);
                if(dis<=x) temp ^= 1<<(j-1);
            }
            ct[temp]++;
        }
    }///预处理tp[i][k] 缩点
    _inint_();
    S = MAX+p,T = S+1;
    for(int i=0;i>pk&1){
                addedge(MAX+pk,i,q[k].a);
                addedge(i,MAX+pk,0);
            }
        }
    }
    for(int i=0;i

 

你可能感兴趣的:(其他比赛的题解,网络流)