zoukankan      html  css  js  c++  java
  • 【HNOI】五彩斑斓 模拟

      【题目描述】

         给定一个n*m的矩阵,矩阵的某些位置有一个颜色(可以没有颜色,即为0),现在你可以将矩阵的某一行或者某一列染成同一种颜色,问最少用多少步能达到目标矩阵的染色方案,输出最少步数和方案。

      【数据范围】

        n,m<=50。颜色数<=60。

      首先我们贪心的知道,矩阵的每一行/列最多会被染色一次,所以染色的目前的上限是n+m。而且每染一次,肯定至少减少矩阵的一行/一列,最坏情况下,其中一次染色的贡献只有1*1的矩阵,对于这个1*1的矩阵,我们不必染两次,所以染色的上限其实是n+m-1。

      这样我们知道肯定有其中某一行(列情况类似)没有被染色,那么我们枚举这一行,那么我们可以根据这个没有染色的得出与该行相交的列的染色情况,那么我们现在知道了所有的列的染色情况,我们再枚举每一行,通过这一行的其余颜色可以判定这一行的颜色或者是否合法,而且我们根据这一行与已知列相交的地方的颜色,我们可以得到该行与每一列染色的前后顺序,如果顺序组成的图是DAG就说明有解,且需要染色的行/列就是答案,取最优就好了。

      反思:开始对于某一行和已知列颜色相同的时候觉得不需要特判,所以就直接让一个在另一个前,这样其实是不行的,他们之间应该不连边,代表没有顺序要求。 

         写没有染色的地方的时候没有特判,最后程序跑的是0可以被当做一种颜色染,然后就跪了。

         写列的时候照着行写的,结果好几个地方不一样也没改,然后又跪了= =。

    //By BLADEVIL
    #include <cstdio>
    #include <cstring>
    #define maxn 60
    #define inf (~0U>>1)
    
    using namespace std;
    
    struct rec {
        int sum;
        int topo[maxn<<1],col[maxn<<1];
        rec() {
            sum=inf;
            memset(topo,0,sizeof topo);
            memset(col,0,sizeof col);
        }
    }ans;
    
    int n,m,k,l;
    int a[maxn][maxn],judge[maxn<<1],last[maxn<<1],other[maxn*maxn],pre[maxn*maxn];
    int cnt[maxn<<1],que[maxn<<1];
    
    void connect(int x,int y) {
        pre[++l]=last[x];
        last[x]=l;
        other[l]=y;
        //printf("%d %d
    ",x,y);
    }
    
    bool topo() {
        memset(cnt,0,sizeof cnt);
        memset(que,0,sizeof que);
        for (int i=1;i<=n+m;i++)
            for (int p=last[i];p;p=pre[p]) cnt[other[p]]++;
        int h=0,t=0;
        for (int i=1;i<=n+m;i++) if (!cnt[i]) que[++t]=i;
        while (h<t) {
            int cur=que[++h];
            for (int p=last[cur];p;p=pre[p]) {
                cnt[other[p]]--;
                if (!cnt[other[p]]) que[++t]=other[p];
            }
        }
        //printf("%d
    ",t);
        return (t==n+m);
    }
    
    void work(int x) {
        memset(judge,-1,sizeof judge);
        memset(last,0,sizeof last);
        l=0;
        if (x<=n) {
            for (int i=1;i<=m;i++) judge[i+n]=a[x][i];
            for (int i=1;i<=n;i++) if (i!=x) {
                for (int j=1;j<=m;j++) if (judge[j+n]!=a[i][j]) {
                    if ((judge[i]!=-1)&&(judge[i]!=a[i][j])) return ;
                    judge[i]=a[i][j];
                    if (!judge[i]) return ;
                    connect(j+n,i);
                }
                for (int j=1;j<=m;j++) if ((judge[j+n]==a[i][j])&&(judge[j+n]!=judge[i])) connect(i,j+n);
            }
        } else {
            for (int i=1;i<=n;i++) judge[i]=a[i][x-n];
            for (int i=1;i<=m;i++) if (i+n!=x) {
                for (int j=1;j<=n;j++) if (judge[j]!=a[j][i]) {
                    if ((judge[i+n]!=-1)&&(judge[i+n]!=a[j][i])) return ;
                    judge[i+n]=a[j][i];
                    if (!judge[i+n]) return ;
                    connect(j,i+n);
                } 
                for (int j=1;j<=n;j++) if ((judge[j]==a[j][i])&&(judge[j]!=judge[i+n])) connect(i+n,j);
                //else connect(i+n,j);
            }
        }
        if (topo()) {
            int cur=0;
            for (int i=1;i<=n+m;i++) if ((judge[i]!=-1)&&(judge[i])) cur++;
            if (cur<ans.sum) {
                ans.sum=cur;
                for (int i=1;i<=n+m;i++) ans.topo[i]=que[i],ans.col[i]=judge[que[i]];
            }
        }
        //printf("%d
    ",x);
        //for (int i=1;i<=n+m;i++) printf("%d ",judge[i]); printf("
    ");
    }
    
    
    int main() {
        freopen("iridescent.in","r",stdin); freopen("iridescent.out","w",stdout);
        scanf("%d%d%d",&n,&m,&k);
        for (int i=1;i<=n;i++)
            for (int j=1;j<=m;j++) scanf("%d",&a[i][j]);
        for (int i=1;i<=n+m;i++) work(i);
        //work(51);
        if (ans.sum==inf) printf("-1
    "); else {
            printf("%d
    ",ans.sum);
            for (int i=1;i<=n+m;i++) {
                if (ans.col[i]==-1) continue;
                if (!ans.col[i]) continue;
                if (ans.topo[i]>n) printf("C %d",ans.topo[i]-n); else printf("R %d",ans.topo[i]);
                printf(" %d
    ",ans.col[i]);
            }
        }
        fclose(stdin); fclose(stdout);
        return 0;
    }
  • 相关阅读:
    28
    27
    26
    25
    24
    23
    17
    16
    15
    14
  • 原文地址:https://www.cnblogs.com/BLADEVIL/p/3635442.html
Copyright © 2011-2022 走看看