【程式設計大賽刷題記錄】C語言 06

weixin_49736885發表於2020-11-10

【奇數碼問題】
連結:https://ac.nowcoder.com/acm/contest/1001/F
來源:牛客網

你一定玩過八數碼遊戲,它實際上是在一個33的網格中進行的,1個空格和1~8這8個數字恰好不重不漏地分佈在這33的網格中。
例如:
5 2 8
1 3 _
4 6 7
在遊戲過程中,可以把空格與其上、下、左、右四個方向之一的數字交換(如果存在)。
例如在上例中,空格可與左、上、下面的數字交換,分別變成:
5 2 8 5 2 _ 5 2 8
1 _ 3 1 3 8 1 3 7
4 6 7 4 6 7 4 6 _

奇數碼遊戲是它的一個擴充套件,在一個n\times nn×n的網格中進行,其中n為奇數,1個空格和1\sim n\times n-11∼n×n−1這n\times n-1n×n−1個數恰好不重不漏地分佈在n*n的網格中。
空格移動的規則與八數碼遊戲相同,實際上,八數碼就是一個n=3的奇數碼遊戲。
現在給定兩個奇數碼遊戲的局面,請判斷是否存在一種移動空格的方式,使得其中一個局面可以變化到另一個局面。
【程式碼】

#include<bits/stdc++.h>
using namespace std;
vector <int> a[2];
int c[500500];
int ans;
void merge(vector <int> &a,int l,int mid,int r)  //運用vector的資料結構
{
    int i=l,j=mid+1;  //定義i,j

    for(int k=l;k<=r;k++){
        if(j>r||i<=mid&&a[i]<=a[j]) c[k]=a[i++];  //如果j<r或i<mid並且a[i]小於等於a[j],將a[i]陣列複製到陣列c[k]中
        else c[k]=a[j++],ans+=mid-i+1;
    }

    for(int k=l;k<=r;k++) a[k]=c[k];  //將c[k]複製到a[k]中
}
void guibing(vector <int> &a,int l,int r)
{
    if(l>=r) return;  //如果l大於r,函式輸入錯誤
    int mid=(l+r)>>1;
    guibing(a,l,mid);
    guibing(a,mid+1,r);
    merge(a,l,mid,r);  //呼叫merge()函式//
}
int cal(int k)
{
    ans=0;
    guibing(a[k],0,a[k].size()-1);  //呼叫guibing()函式
    return ans;
}
int main()
{
    int n;
    while(cin>>n){
        a[0].clear();  //清空資料
        a[1].clear();

        for(int i=1,u;i<=n*n;i++){
            cin>>u;
            if(u) a[0].push_back(u);  //尾部加入一個資料
        }
        for(int i=1,u;i<=n*n;i++){
            cin>>u;
            if(u) a[1].push_back(u);
        }

        puts(a[0].size()&&(cal(1) - cal(0) & 1) ? "NIE" : "TAK");  //判斷輸出“NIE”或“TAK”

        //cout<<"ans="<<cal(0)<<endl;  //通過對函式cal()的呼叫實現對前面兩個子函式的呼叫,輸出答案

    }
    return 0;
}

相關文章