1. 程式人生 > 其它 >F. Alice and Recoloring 1&2

F. Alice and Recoloring 1&2

F1. Alice and Recoloring 1

題意:給定一個 n * m 的 0 1 矩陣,你需要使用以下四種操作使得個矩陣全為 0 ,求出最小的代價。

  • 代價為 1 的第一種操作:反轉矩陣的某個左上子矩陣。
  • 代價為 2 的第二種操作:反轉矩陣的某個左下子矩陣。
  • 代價為 4 的第三種操作:反轉矩陣的某個右上子矩陣。
  • 代價為 3 的第四種操作:反轉矩陣的某個右下子矩陣。

分析:

  • 首先需要發現第二種和第三種操作是可以被第一種操作替代的,且代價不會更高。
  • 將原先的矩陣做差分。原先對關於(x,y)的子矩陣的操作,對於差分後的矩陣,第一種操作等價於反轉(x,y)一個單元,第四種操作相當於反轉(x-1,y-1),(x-1,m),(n,y-1),(n,m)這四個單元。
  • 考慮第四種操作什麼時候是有意義的,顯現需要這個操作使得四個單元都由 0 變成 1 。又由於它們都是關於(n,m)的,所以該操作最多執行一次。
#include<bits/stdc++.h>
#define ll long long
#define ls u<<1
#define rs u<<1|1
#define mm(x) memset(x,0,sizeof(x))
#define debug(x) cout << #x << ":" << x << '\n'
using namespace std;
int
read() { int a=0;int f=0;char p=getchar(); while(!isdigit(p)){f|=p=='-';p=getchar();} while(isdigit(p)){a=(a<<3)+(a<<1)+(p^48);p=getchar();} return f?-a:a; } const int INF=998244353; int T; int n,m; int ans; char s[550][550]; bool val[550][550]; int main() { n=read(); m=read();
for(int i=1;i<=n;++i) scanf("%s",s[i]+1); for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) val[i][j]=s[i][j]=='B'; for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) val[i][j]^=val[i+1][j]^val[i][j+1]^val[i+1][j+1]; ans=val[n][m]; for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) { if(i==n&&j==m) continue; if(val[i][j]) { ans++; if(i==n) continue; if(j==m) continue; if(val[i][m]&&val[n][j]&&val[n][m]) { ans--; val[n][m]=false; } } } printf("%d",ans); return 0; }
View Code

F2. Alice and Recoloring 2

題意:給定一個 n * m 的 0 1 矩陣,你需要使用以下四種操作使得個矩陣全為 0 ,求出最小的代價。

  • 代價為 1 的第一種操作:反轉矩陣的某個左上子矩陣。
  • 代價為 2 的第二種操作:反轉矩陣的某個左下子矩陣。
  • 代價為 4 的第三種操作:反轉矩陣的某個右上子矩陣。
  • 代價為 2 的第四種操作:反轉矩陣的某個右下子矩陣。

分析:相比於前一題,第四種操作的代價變小了。造成的結果是,第四種操作能執行多次。

  • 依舊是首先將原先的矩陣做差分。
  • 考慮第四種操作作用的點。假設對於同一行或者同一列的兩個單元執行第四種操作,那麼我們相當於花費了 4 的代價反轉了 4 個單元。並不比第一種操作更加節約,因此我們避免這種操作。
  • 繼續考慮第四種操作,如果個操作影響的四個單元中為 1 的個數少於或者等於三個,考慮到要把至少一個單元反轉回來,顯然也不會更節約。
  • 由於(n,m)是所有第四種操作都會影響的單元,我們暫時先不考慮它。我們考慮是否要對一個單元(x,y)執行第四種操作時,首先保證(x,y),(x,m),(n,y)都為 1 ,將它加入備選佇列。
  • 接下來我們需要的是在備選佇列中選出儘可能多的點,滿足沒有任意兩個點的 X 或者 Y 相等(這是一個經典的關於網格的二分圖匹配問題)。
#include<bits/stdc++.h>
#define ll long long
#define ls u<<1
#define rs u<<1|1
#define mm(x) memset(x,0,sizeof(x))
#define debug(x) cout << #x << ":" << x << '\n'
using namespace std;
int read()
{
    int a=0;int f=0;char p=getchar();
    while(!isdigit(p)){f|=p=='-';p=getchar();}
    while(isdigit(p)){a=(a<<3)+(a<<1)+(p^48);p=getchar();}
    return f?-a:a;
}
const int INF=998244353;
int T;
int n,m;
int ans,tot;
char s[550][550];
bool val[550][550];
bool link[550][550];
int mat[550];
int vis[550];
bool dfs(int u,int t)
{
    for(int i=1;i<=m;++i)
    {
        if(link[u][i]&&vis[i]!=t)
        {
            vis[i]=t;
            if(!mat[i]||dfs(mat[i],t))
            {
                mat[i]=u;
                return true;
            }
        }
    }
    return false;
}
int main()
{
    n=read();    m=read();
    for(int i=1;i<=n;++i)    scanf("%s",s[i]+1);
    for(int i=1;i<=n;++i)
        for(int j=1;j<=m;++j)
            val[i][j]=s[i][j]=='B';
    for(int i=1;i<=n;++i)
        for(int j=1;j<=m;++j)
        {
            val[i][j]^=val[i+1][j]^val[i][j+1]^val[i+1][j+1];
            ans+=val[i][j]; 
        }
    for(int i=1;i<n;++i)
        for(int j=1;j<m;++j)
            if(val[i][j]&&val[i][m]&&val[n][j])
                link[i][j]=true;
    for(int i=1;i<=n;++i)
        if(dfs(i,i))    ++tot;
    ans-=val[n][m];
    ans-=tot;
    if((tot^val[n][m])&1)    ans++;
    printf("%d",ans);
    return 0;
}
View Code