1. 程式人生 > >Fliptile奶牛踩瓷磚 (狀態壓縮,開關問題,枚舉)

Fliptile奶牛踩瓷磚 (狀態壓縮,開關問題,枚舉)

狀態壓縮 .net amp ref with 枚舉 tar brush tps

題目:Fliptile

題意:

給定一個M*N矩陣,有些是黑色(1表示)否則白色(0表示),每翻轉一個(i,j),會使得它和它周圍4個格變為另一個顏色,要求翻轉最少的點,使得變為全白色的矩陣,輸出這個標記了翻轉點的矩陣,如果有多個最優解,輸出逆字典序最小的那個矩陣,若沒有解,輸出IMPOSSIBLE。

題解:

參考:Fliptile POJ3279 二進制壓縮枚舉 解題報告

只要第一行的方案確定,後面的踩發就能確定,所以狀壓枚舉第一行的方案

代碼:

/***********************************************/
int ans[30][30];
int a[34][34];
int b[33][33];
int m,n;
int ANS=inf;
ll daan=-1;

int fanzhuan1(ll Y)
{
    mem0(ans);
    int pp=0;
    for(int i=1;i<=m;i++)
        for(int j=1;j<=n;j++) a[i][j]=b[i][j];
    for(int i=0;i<n;i++)
    {
        if(Y&(1ll<<i)) //翻轉第一行第n-i個
        {
            pp++;
            ans[1][n-i]=1;
            a[1][n-i]=a[1][n-i]?0:1;
            if(i>0) a[1][n-i+1]=a[1][n-i+1]?0:1;
            if(i<n-1) a[1][n-i-1]=a[1][n-i-1]?0:1;
            if(n>1) a[2][n-i]=a[2][n-i]?0:1;
        }
    }

    return pp;
}

void solve(int pp,ll p1)
{

    for(int i=1;i<m;i++)
    {
        for(int j=n;j>=1;j--)
        {
            if(a[i][j])
            {
                ans[i+1][j]=1;
                a[i][j]=0;
                a[i+1][j]=a[i+1][j]?0:1;
                if(j>1) a[i+1][j-1]=a[i+1][j-1]?0:1;
                if(j<n) a[i+1][j+1]=a[i+1][j+1]?0:1;
                if(i+2<=m) a[i+2][j]=a[i+2][j]?0:1;
            }
        }
    }
    for(int j=1;j<=n;j++)
    {
        if(a[m][j]){
            //cout<<"IMPOSSIBLE"<<endl;
            return ;
        }
    }
    ///取最優
    int sum=pp;
    for(int i=1;i<=m;i++)
    for(int j=1;j<=n;j++)
    {
        if(ans[i][j]) sum++;
    }
    if(sum<ANS)
    {
        ANS=sum;
        daan=p1;
    }
}

int main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    cin>>m>>n;
    for(int i=1;i<=m;i++)
        for(int j=1;j<=n;j++) cin>>b[i][j];

    int Y=(1<<n)-1;
    for(ll i=0;i<=Y;i++)
    {
        int t=fanzhuan1(i);
        //cout<<t<<endl;
        solve(t,i);
    }
    if(daan==-1) cout<<"IMPOSSIBLE"<<endl;
    else
    {
        //cout<<daan<<endl;
        int t=fanzhuan1(daan);
        solve(t,daan);
        for(int i=1;i<=m;i++)
        {
            for(int j=1;j<n;j++) cout<<ans[i][j]<<" ";
            cout<<ans[i][n]<<endl;
        }
    }


    return 0;
}

  

Fliptile奶牛踩瓷磚 (狀態壓縮,開關問題,枚舉)