1447:靶形數獨(可行性剪枝 ~好題)

【題目描述】

 

 

const int N=11+5;
const int grade[10][10]{
{0,0,0,0,0,0,0,0,0,0},
{0,6,6,6,6,6,6,6,6,6},
{0,6,7,7,7,7,7,7,7,6},
{0,6,7,8,8,8,8,8,7,6},
{0,6,7,8,9,9,9,8,7,6},
{0,6,7,8,9,10,9,8,7,6},
{0,6,7,8,9,9,9,8,7,6},
{0,6,7,8,8,8,8,8,7,6},
{0,6,7,7,7,7,7,7,7,6},
{0,6,6,6,6,6,6,6,6,6},
};
const int part[10][10]{
{0,0,0,0,0,0,0,0,0,0},
{0,1,1,1,2,2,2,3,3,3},
{0,1,1,1,2,2,2,3,3,3},
{0,1,1,1,2,2,2,3,3,3},
{0,4,4,4,5,5,5,6,6,6},
{0,4,4,4,5,5,5,6,6,6},
{0,4,4,4,5,5,5,6,6,6},
{0,7,7,7,8,8,8,9,9,9},
{0,7,7,7,8,8,8,9,9,9},
{0,7,7,7,8,8,8,9,9,9},
};

    int n,m,t;
    int i,j,k;
    int maxx,num;
    bool vis[N*10]; //記錄爲 0 的格子的狀態
    bool vis_x[N][N],vis_y[N][N],vis_g[N][N]; //記錄橫行,縱列,小九宮格所包含的元素
    int G[N][N]; //保存整個九宮格的數據
    Pair p[N*10];

inline bool valid(int x,int aim){ //判斷此行,此列 及 小九宮格是否包含目標元素 aim
    if(vis_x[ p[x].fr ][aim]) return false;
    if(vis_y[ p[x].sc ][aim]) return false;
    if(vis_g[ part[ p[x].fr ][ p[x].sc ] ][aim]) return false;
    return true;
}
void DFS(int step)
{
    if(step>num){
        int ans=0;
        for(int i=1;i<=9;i++){
            for(int j=1;j<=9;j++){
                ans+=G[i][j]*grade[i][j];
            }
        }
        maxx=max(ans,maxx);
        return ;
    }

    //尋找每個格子中擁有 最小選擇選擇數的格子進行填充
    //可行性剪枝
    int minn=inf,aim;
    for(int i=1;i<=num;i++){  //枚舉還未填入的格子
        if(!vis[i]){
            int cur=0;
            for(int j=1;j<=9;j++){  //枚舉每個可能填入的數
                if( valid(i,j) ){
                    if(++cur==minn) break;
                }
            }
            if(cur<minn){
                minn=cur;
                aim=i;
            }
        }
    }

    vis[aim]=1;
    int x=p[aim].fr;
    int y=p[aim].sc;
    for(int i=1;i<=9;i++){
        if( valid(aim,i) ){
            G[x][y]=i;
            vis_x[x][i]=1;
            vis_y[y][i]=1;
            vis_g[ part[x][y] ][i]=1;

            DFS(step+1);

            vis_x[x][i]=0;
            vis_y[y][i]=0;
            vis_g[ part[x][y] ][i]=0;
        }
    }
    vis[aim]=0;

}
int main()
{
    //IOS;
    num=0;
    for(i=1;i<=9;i++){
        for(j=1;j<=9;j++){
            cin>>G[i][j];
            if(G[i][j]){
                vis_x[i][ G[i][j] ]=1; //橫行上有了 G[i][j] 元素
                vis_y[j][ G[i][j] ]=1; //縱列上有了 G[i][j] 元素
                vis_g[ part[i][j] ][ G[i][j] ]=1; //小九宮格上有 G[i][j]元素
            }
            else{
                num++;
                p[num].fr=i; //橫行
                p[num].sc=j; //縱列
            }
        }
    }
    maxx=-1;
    DFS(1);
    cout<<maxx<<endl;
    //PAUSE;
	return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章