1 条题解

  • 0
    @ 2025-8-24 22:54:19

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar LRC0511
    退役了

    搬运于2025-08-24 22:54:19,当前版本为作者最后更新于2024-01-18 19:03:49,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    提供一个好写的做法。

    首先考虑 R=nR=n 时怎么做,此时我们可以确定所有行剩余部分可以填的数的集合,我们只需保证每一列的数不重复就够了。

    我们将每一行作为左部点,每种数作为右部点,如果该行可以填某个数则连一条边,这是一张二分图,且每个点的度数均为 nCn-C

    根据上面的讨论,我们需要将其划分成 nCn-C 组完美匹配,每一组匹配确定了每一列填哪些数。

    我们知道,一张二分图的边染色数是它每个点度数的最大值。因此我们可以求出这张图的一个 nCn-C 边染色,对于每种颜色的所有边,易知它们构成了一组完美匹配。

    只需要利用 CF600F 的方法求一次二分图边染色即可,时间复杂度 O(n3)O(n^3)

    再考虑 RnR \neq n 的情况。我们考虑先填左下角的部分,将问题转化为 R=nR=n 的情况。

    同样可以确定前 CC 列可填的数的集合,利用同样的方式建图,我们得到了一张左部点度数均为 nRn-R 的二分图。

    如果某个右部点的度数大于 nRn-R,这意味着某个数出现的次数超过 nRn-R,但是未填的 nRn-R 行中,每行至多填一个,因此此时必然无解。

    所以该二分图有 nRn-R 边染色,每种颜色的边对应一组左部满的匹配,对应每一行所填的数的集合。

    只需再跑一次二分图边染色即可,时间复杂度 O(n3)O(n^3)

    代码如下:

    #include <bits/stdc++.h>
    using namespace std;
    const int N=505;
    int n,r,c,a[N][N],to[N*2][N];
    namespace Paint
    {
        inline void init(int n,int d)
        {
            for(int i=1;i<=n;i++)
                for(int j=1;j<=d;j++)
                    to[i][j]=0;
        }
        void dfs(int u,int v,int x,int y)//x->y
        {
            if(!to[v][y]){to[u][y]=v,to[v][y]=u,to[v][x]=0;return;}
            int w=to[v][y];
            if(to[w][x]) dfs(w,to[w][x],x,y);
            else to[w][y]=0;
            to[w][x]=v,to[v][x]=w,to[v][y]=u,to[u][y]=v;
        }
        inline void add(int u,int v)
        {
            int x=1,y=1;while(to[u][x]) x++;
            while(to[v][y]) y++;
            if(x==y){to[u][x]=v,to[v][y]=u;return;}
            dfs(u,v,y,x);
        }
    }
    int tmp[N];
    bool work1()
    {
        for(int i=1;i<=n;i++) tmp[i]=c;
        for(int i=1;i<=r;i++)
            for(int j=1;j<=c;j++)
                tmp[a[i][j]]--;
        for(int i=1;i<=n;i++)
            if(tmp[i]>n-r) return 0;
        Paint::init(n+c,n-r);
        for(int j=1;j<=c;j++)
        {
            for(int i=1;i<=n;i++) tmp[i]=0;
            for(int i=1;i<=r;i++) tmp[a[i][j]]=1;
            for(int i=1;i<=n;i++)
                if(!tmp[i]) Paint::add(j,c+i);
        }
        for(int j=1;j<=c;j++)
            for(int i=r+1;i<=n;i++)
                a[i][j]=to[j][i-r]-c;
        return 1;
    }
    void work2()
    {
        Paint::init(2*n,n-c);
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++) tmp[j]=0;
            for(int j=1;j<=c;j++) tmp[a[i][j]]=1;
            for(int j=1;j<=n;j++)
                if(!tmp[j]) Paint::add(i,n+j);
        }
        for(int i=1;i<=n;i++)
            for(int j=c+1;j<=n;j++)
                a[i][j]=to[i][j-c]-n;
    }
    void work()
    {
        cin>>n>>r>>c;bool fl=1;
        for(int i=1;i<=r;i++)
            for(int j=1;j<=c;j++)
                cin>>a[i][j];
        if(r<n) fl=work1();
        if(fl) work2();
        if(!fl){cout<<"No\n";return;}
        cout<<"Yes\n";
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                cout<<a[i][j]<<" \n"[j==n];
    }
    int main()
    {
        ios::sync_with_stdio(false);
        cin.tie(0),cout.tie(0);
        int T;cin>>T;while(T--) work();
        return 0;
    }
    
    • 1

    信息

    ID
    9719
    时间
    5000ms
    内存
    1024MiB
    难度
    7
    标签
    递交数
    0
    已通过
    0
    上传者