[HNOI2013]消毒

壹、题目

传送门

贰、思考

每次消毒使用 \(\min\{x,y,z\}\) 单位的药,只需要让其中一个是 \(1\),剩下的取最大?似乎可以?

或者从简单想起,从低维想。

2.1.一维弱化版

直接输出 \(1\) 的个数。

2.2.二维弱化版

矩阵是 \(n\times m\) 的。

贪心地,消毒一定选择 \(\{1,m\}\) 或者 \(\{n,1\}\),从几何上来看,就是清空一行或者一列。

如果有一个点 \((x,y)\) 需要消毒,那么一定是 \(x\) 或者 \(y\) 或者两排一起消。进一步推到:如果有一个点 \((x,y)\) 需要消毒,那么就从 \(x\rightarrow y\),然后求最小点覆盖(最大匹配)。

2.3.三维原版

实验室尺寸是 \(a\times b\times c\) 的。

继承二维,贪心地说,我们每次清空一个面,如果一个点需要清空,那么一定是三个面中的一个,一个点需要涉及三个面?这个怎么做?

注意到 \(\mathcal a\times b\times c\le 5000\),那么一定有 \(\min\{a,b,c\}\le 17\).

布吉岛怎么用......

叁、题解

好吧,直接暴力我佛了。

\(2^{\rm min}\) 枚举最小的那一维的每一层是消毒还是不消毒,剩下的就是二维上的问题了。

肆、代码

using namespace Elaina;

const int maxn=5e3;
const int inf=maxn+5;

int cnt;
int pos[4][maxn+5];
int a,b,c,minn;

int ans;

inline void input(){
    cnt=0,ans=inf;
    a=readin(1),b=readin(1),c=readin(1);
    minn=Min(a,Min(b,c));
    rep(i,1,a)rep(j,1,b)rep(k,1,c){
        if(!readin(1))continue;
        ++cnt;
        pos[1][cnt]=i;
        pos[2][cnt]=j;
        pos[3][cnt]=k;
    }
    if(minn==b)swap(a,b),swap(pos[1],pos[2]);
    else if(minn==c)swap(a,c),swap(pos[1],pos[3]);
}

struct edge{int to,nxt;}e[maxn*maxn+5];
int tail[maxn+5],ecnt;
inline void add_edge(const int u,const int v){
    e[++ecnt]=edge{v,tail[u]};tail[u]=ecnt;
}
inline void build(const int s){
    memset(tail+1,0,b<<2);ecnt=0;
    for(int i=1;i<=cnt;++i)if(!((s>>(pos[1][i]-1))&1))
        add_edge(pos[2][i],pos[3][i]);
}
int vis[maxn+5],match[maxn+5];
int hungary(const int u){
    for(int i=tail[u],v;i;i=e[i].nxt)if(!vis[v=e[i].to]){
        vis[v]=1;
        if(!match[v] || hungary(match[v])){
            match[v]=u;
            return 1;
        }
    }
    return 0;
}
int Ans;
inline int count(int s){
    int ret=0;
    for(;s;s>>=1)ret+=(s&1);
    return ret;
}
inline void work(const int s){
    build(s);
    int ans=count(s);
    memset(match+1,0,c<<2);
    for(int i=1;i<=b;++i){
        memset(vis+1,0,c<<2);
        if(hungary(i))++ans;
    }
    Ans=Min(Ans,ans);
}

signed main(){
    rep(i,1,readin(1)){
        input();Ans=inf;
        for(int i=0;i<(1<<a);++i)
            work(i);
        writc(Ans,'\n');
    }
    return 0;
}

肆、用到の小 \(\tt trick\)

遇到类似 \(\prod_{i=1}^na_i\le x\),那么需要意识到 \(\min\{a_i\}\le \sqrt[n]{x}\),类似地,遇到 \(\sum_{i=1}^na_i\le x\),就有 \(min\{a_i\}\le {x\over n}\).

从简单想起,遇到高维情况,或者其他较为复杂的情况,可以考虑先简化一下问题,去掉一些限制或者降维思考,然后逐渐增加限制.

还有就是这种二分图匹配的类型,由于点必须被消毒,那么就要求对于一个点 \((x,y,z)\) 一定会选择至少一维作为消毒对象,这可以转化为最小点覆盖进而求最大匹配.

posted @ 2021-02-05 16:46  Arextre  阅读(88)  评论(0)    收藏  举报