习题: [HNOI2013]消毒(匈牙利)

题目

传送门

思路

我们先考虑低维的情况

一维

这应该有手就行

可惜我没有手

二维

我们注意到,我们肯定都是一次性将一次一行或者一列直接覆盖完全,这一定是最优的方法

之后我们观察一个矩阵,其只需要\(min(x,y)\)条线段就可以覆盖完全,这刚好就是题目中所提到的代价计算方式

然后就可以转换成为最小点覆盖的问题

三维

三维的情况也有点类似,我们每一次一定是将一个面删去,

然后你会发现不会三分图匹配这种玩意,所以考虑暴力枚举一维,剩下的两维二分图匹配即可

代码

#include<iostream>
#include<cstring>
#include<vector>
#include<cstdio>
using namespace std;
vector<int> g[5005];
int T;
int a,b,c;
int minn,tot;
int dir[4][5005],ans;
int mat[5005],vis[5005];
int used[5005];
void init()
{
    ans=(1<<30);
    tot=0;
    memset(dir,0,sizeof(dir));
}
bool dfs(int u,int tag)
{
    if(vis[u]==tag)
        return 0;
    vis[u]=tag;
    for(int i=0;i<g[u].size();i++)
    {
        int v=g[u][i];
        if(mat[v]==0||dfs(mat[v],tag))
        {
            mat[v]=u;
            return 1;
        }
    }
    return 0;
}
void solve(int s)
{
    int ret=0;
    for(int i=1;i<=tot;i++)
        g[i].clear();
    memset(mat,0,sizeof(mat));
    for(int i=1;i<=a;i++)
    {
        if(s&(1<<(i-1)))
        {
            ret++;
            used[i]=0;
        }
        else
            used[i]=1;
    }
    for(int i=1;i<=tot;i++)
        if(used[dir[1][i]])
            g[dir[2][i]].push_back(dir[3][i]);
    for(int i=1;i<=b;i++)
    {
        memset(vis,0,sizeof(vis));
        if(dfs(i,i))
            ret++;
    }
    ans=min(ans,ret);
}
void c_in()
{
    init();
    cin>>a>>b>>c;
    minn=min(a,min(b,c));
    for(int i=1;i<=a;i++)
        for(int j=1;j<=b;j++)
            for(int k=1;k<=c;k++)
            {
                int x;
                cin>>x;
                if(x)   
                {
                    tot++;
                    dir[1][tot]=i;
                    dir[2][tot]=j;
                    dir[3][tot]=k;
                }
            }
    if(b==minn)
    {
        swap(a,b);
        swap(dir[1],dir[2]);
    }
    else if(c==minn)
    {
        swap(a,c);
        swap(dir[1],dir[3]);
    }
    /*for(int i=1;i<=3;i++)
    {
        for(int j=1;j<=tot;j++)
            cout<<dir[i][j]<<' ';
        cout<<'\n';
    }*/
    for(int i=0;i<(1<<a);i++)
        solve(i);
    cout<<ans<<'\n';
}
int main()
{
    cin>>T;
    for(int i=1;i<=T;i++)
        c_in();
    return 0;
}
posted @ 2021-02-04 20:50  loney_s  阅读(64)  评论(0)    收藏  举报