zoukankan      html  css  js  c++  java
  • CS Academy Round#2 E.Matrix Coloring

    题目链接

    Round#2 E.Matrix Coloring

    题目大意

    有一个 (N imes M) 的方格图,开始每个格子是白的,接下来每次操作可以把某一行或某一列全部染成红色或蓝色,这里的染色会覆盖一个格子曾经的颜色。现在给出方格图最终的状态(没有白色格子剩余),求最少需要多少次操作把空白的图染成这个状态,若无解则输出 (-1)

    (1leq N,Mleq 3000)

    思路

    答案的上限为 (N+M) ,下限为 (min{N,M})。操作次数最少 (iff) 没被直接染的行和列的数量尽量多,而每一个格子至少被染过一遍,从而没有被染的要么全是行,要么全是列,这里不妨设是行,由于对于没被直接染的行,其颜色状态直接由列的染色情况决定,是唯一的,所以所有没被染的行它们在最终的图上的状态应是完全一样的。

    这样子看来我们只需要贪心地找重复次数最多的状态即可,那么该如何判断一个状态是否有解呢?这里先给出结论:任意一个不染的局面有解 (iff) 原局面有解,充分性显然,必要性的证明:

    (1) 被钦定不染的行的状态是完全相同的,说明在原局面的一个解中,若这些行存在没被染的,那么把他们统一改成不染的情况并不会改变最终状态,则该钦定的局面有解,所以我们只需要考虑这些行全部被染的情况。
     
    (2) 在这个解中行全部被染,考虑把染行这个操作变成把列按照这些行的最终状态全染一遍,把这个操作放在最开始,然后删去这些行,接下来我们染别的地方时无视这个处理,就当网格图还是全白的,然后将原解中除了染这些行以外的操作套上去,可以发现这样我们依然得到了最终的状态,而这个改进的方案是不染这些行的局面的一个解。
     
    综上,原局面有解 (Rightarrow) 该不染的局面有解.

    根据这个结论,只要题目存在任意一组解,我们就可以直接拿重复最多的状态计算答案了。找到一组解的方法很容易,每次我们找到一个元素全部相同的行或列,将其删除,一直做下去,若图最后能被删完,则有解。

    时间复杂度 (O(NM))

    Code

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<vector>
    #include<map>
    #define rep(i,a,b) for(int i = (a); i <= (b); i++)
    #define per(i,b,a) for(int i = (b); i >= (a); i--)
    #define N 3030
    using namespace std;
    vector<int> p[N];
    map<vector<int>, int> cnt;
    bool visr[N], visc[N];
    int n, m, row[N], col[N];
    int ans;
    void solve(){
        cnt.clear();
        int mx = 0;
        rep(i,0,n-1) mx = max(mx, ++cnt[p[i]]);
        ans = min(ans, n+m-mx);
    }
    bool able(){
        rep(i,0,n-1) rep(j,0,m-1)
            row[i] += p[i][j], col[j] += p[i][j];
        int r = n, c = m;
        while(r > 0 && c > 0){
            bool flag = false;
            rep(i,0,n-1) if(!visr[i] && (row[i] == 0 || row[i] == c)){
                flag = visr[i] = true, r--;
                rep(j,0,m-1) col[j] -= p[i][j];
            }
            if(flag) continue;
            rep(j,0,m-1) if(!visc[j] && (col[j] == 0 || col[j] == r)){
                flag = visc[j] = true, c--;
                rep(i,0,n-1) row[i] -= p[i][j];
            }
            if(!flag) return false;
        }
        return true;
    }
    int main(){
        cin>>n>>m;
        char ch = getchar();
        rep(i,0,max(n, m)-1) p[i].resize(max(n, m));
        rep(i,0,n-1){
            rep(j,0,m-1) ch = getchar(), p[i][j] = (ch == 'R');
            ch = getchar();
        }
        if(!able()){
            puts("-1"); return 0;
        }
        ans = n+m;
        solve();
        rep(i,0,n-1) rep(j,i,m-1) swap(p[i][j], p[j][i]);
        swap(n, m);
        solve();
        cout<<ans<<endl;
        return 0;  
    }
    

    (p.s.) 官方题解好像有点不严谨,其建图后的结论不大好证,也没法感性理解 (QAQ)

  • 相关阅读:
    活动设计的“七宗罪”(转)
    BAYESIAN STATISTICS AND CLINICAL TRIAL CONCLUSIONS: WHY THE OPTIMSE STUDY SHOULD BE CONSIDERED POSITIVE(转)
    iOS开发—— UIImagePickerController获取相册和拍照
    iOS开发——UIImageView
    iOS开发——导入第三方库引起的unknown type name 'NSString'
    iOS开发——UITableView(未完,待续...)
    iOS开发——Reachability和AFNetworking判断网络连接状态
    iOS开发——GCDAsyncSocket
    iOS开发——pch文件创建
    iOS开发——打开手机相册,获取图片
  • 原文地址:https://www.cnblogs.com/Neal-lee/p/14691714.html
Copyright © 2011-2022 走看看