HDU 4069 Squiggly Sudoku【舞蹈链】【样例坑】

建模思路跟之前的一样,宫的话dfs搜索一下找联通分量就行,好像也没有更好的办法,有的话请评论哈orz

——因为舞蹈链一般找到解以后就直接跳出了,所以ans数组就是ans不会再变。但这题让找一下有没有多组解,所以就不能找到一个解后直接跳出。就有一个小坑是都搜完后ans数组可能不是合法ans,所以找到第一个解的时候要单独存一下才能ac

——但这个样例就是如果中间不存一下ans数组的话,样例还是能过。。。

——那应该就是正好最后一次枚举的时候找到了这个解??

——不然的话它回溯的时候枚举下一个可能会覆盖原来ans数组的

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<iomanip>
#include<algorithm>
#include<vector>
#define INF 2e9
#define maxnode 100000

using namespace std;
int dx[4]={0,0,1,-1};
int dy[4]={1,-1,0,0};

int board[10][10],vis[100],an[100];
vector<int> edge[100];

int cnt;
void dfs(int u){
    vis[u]=cnt;
    for(int i=0;i<edge[u].size();i++){
        int v=edge[u][i];
        if( !vis[v] ) dfs(v);
    }
}

struct DLX{
    int up[maxnode],down[maxnode],L[maxnode],R[maxnode];
    int row[maxnode],col[maxnode],h[5000],s[350];
    int n,m,size,ansd,ans[5000];

    void init(int n1,int m1){
        n=n1; m=m1;
        for(int i=0;i<=m;i++){
            up[i]=down[i]=i;
            L[i]=i-1;
            R[i]=i+1;
            s[i]=0;
        }
        L[0]=m; R[m]=0;
        ansd=0; size=m;
        for(int i=1;i<=n;i++) h[i]=-1;
    }

    void link(int r,int c){
        row[++size]=r; col[size]=c;
        s[c]++;
        up[size]=up[c];
        down[size]=c;
        down[up[c]]=size;
        up[c]=size;
        if( h[r]==-1 ) h[r] = L[size] = R[size] = size;
        else{
            L[size]=L[h[r]];
            R[size]=h[r];
            R[L[h[r]]]=size;
            L[h[r]]=size;
        }
    }

    void remove(int c){
        L[R[c]]=L[c];
        R[L[c]]=R[c];
        for(int i=down[c];i!=c;i=down[i]){
            for(int j=R[i];j!=i;j=R[j]){
                up[down[j]]=up[j];
                down[up[j]]=down[j];
                s[ col[j] ]--;//忘写这一行的话会慢很多但不会错
            }
        }
    }

    void resume(int c){
        L[R[c]]=c;
        R[L[c]]=c;
        for(int i=down[c];i!=c;i=down[i]){
            for(int j=R[i];j!=i;j=R[j]){
                up[down[j]]=j;
                down[up[j]]=j;
                s[ col[j] ]++;
            }
        }
    }

    bool dance(int d){
    //    cout<<d<<" "<<R[0]<<endl;
        if( R[0]==0 ){
            if( ansd!=0 ) return true;
            ansd=d;
            for(int i=0;i<81;i++) an[i]=ans[i];
            return false;//目前还没有搜到multiple solution
        }

        int c=R[0];
        for(int i=c;i!=0;i=R[i])
            if( s[i]<s[c] ) c=i;

        remove(c);
        for(int i=down[c];i!=c;i=down[i]){
            ans[d]=row[i];
            for(int j=R[i];j!=i;j=R[j]) remove( col[j] );
            if( dance(d+1) ) return true;
            for(int j=L[i];j!=i;j=L[j]) resume( col[j] );
        }
        resume(c);
        return false;
    }
}dlx;

struct node{
    int r,c,num;
    node(int r1=0,int c1=0,int n1=0): r(r1),c(c1),num(n1) {}
}biao[5000];

int main(){
    ios::sync_with_stdio(false);

    int t; cin>>t;
    int cas=0;
    while(t--){

        memset(vis,0,sizeof(vis));
        for(int i=0;i<100;i++) edge[i].clear();
        cnt=0;

        for(int i=0;i<9;i++){
            for(int j=0;j<9;j++){
                int id=i*9+j+1;
                cin>>board[i][j];

                if( board[i][j]>=128 ) board[i][j]-=128;//左边
                else edge[id].push_back( id-1 );

                if( board[i][j]>=64 ) board[i][j]-=64;
                else edge[id].push_back( id+9 );//down

                if( board[i][j]>=32 ) board[i][j]-=32;//right
                else edge[id].push_back( id+1 );

                if( board[i][j]>=16 ) board[i][j]-=16;//up
                else edge[id].push_back( id-9 );
            }
        }

        for(int i=1;i<=81;i++){
            if( !vis[i] ){
                cnt++;
                dfs(i);
            }
        }

        //这样一来就都分好了宫
        dlx.init(4000,324);
        int rows=0;
        for(int i=0;i<9;i++){
            for(int j=0;j<9;j++){
                int id=i*9+j+1;
                if( board[i][j]==0 ){
                    for(int k=1;k<=9;k++){
                        rows++;
                        dlx.link(rows,id);
                        dlx.link(rows,81+i*9+k);//行
                        dlx.link(rows,162+j*9+k);//列
                        dlx.link(rows,243+(vis[id]-1)*9+k);
                        biao[rows]=node(i,j,k);
                //        cout<<rows<<" "<<id<<" "<<81+i*9+k <<" "<<162+j*9+k <<" "<<243+(vis[id]-1)*9+k<<endl;
                    }
                }
                else{
                    rows++;
                    dlx.link(rows,id);
                    dlx.link(rows,81+i*9+board[i][j]);
                    dlx.link(rows,162+j*9+board[i][j]);
                    dlx.link(rows,243+(vis[id]-1)*9+board[i][j]);
                    biao[rows]=node(i,j,board[i][j]);
                //    cout<<rows<<" "<<id<<" "<<81+i*9+board[i][j] <<" "<<162+j*9+board[i][j] <<" "<<243+(vis[id]-1)*9+board[i][j]<<endl;
                }
            }
        }
        cout<<"Case "<<++cas<<":"<<endl;

        if( dlx.dance(0) ) cout<<"Multiple Solutions"<<endl;
        else if(dlx.ansd){
            for(int i=0;i<=80;i++){
                node p=biao[ an[i] ];
                board[p.r][p.c]=p.num;
            }

            for(int i=0;i<9;i++){
                for(int j=0;j<9;j++) cout<<board[i][j];
                cout<<endl;
            }
        }
        else cout<<"No solution"<<endl;

    }

    return 0;
}

原文地址:https://www.cnblogs.com/ZhenghangHu/p/9745958.html

时间: 2024-08-29 13:16:03

HDU 4069 Squiggly Sudoku【舞蹈链】【样例坑】的相关文章

(中等) HDU 4069 Squiggly Sudoku , DLX+精确覆盖。

Description Today we play a squiggly sudoku, The objective is to fill a 9*9 grid with digits so that each column, each row, and each of the nine Connecting-sub-grids that compose the grid contains all of the digits from 1 to 9. Left figure is the puz

HDU 4069 Squiggly Sudoku Dancing-Links(DLX)+Floodfill

题目大意:..还是数独,不同的是原先的九宫格约束条件变为了给定的任意形状... 我们跑一遍floodfill 得出每一个格子属于哪一个形状 然后就是裸的数独了 这题T<=2500 绝对不能开动态 清则TLE 不清MLE 只能数组模拟 好不容易改完了 尼玛 交上去就WA 最后发现当找到一组解之后 一定要把当前的数独转移到ANS数组中 否则就会被覆盖 导致输出时错误 #include<cstdio> #include<cstring> #include<iostream&g

[DLX+bfs] hdu 4069 Squiggly Sudoku

题意: 给你9*9的矩阵.对于每个数字,能减16代表上面有墙,能减32代表下面有墙... 最后剩下的数字是0代表这个位置数要求,不是0代表这个数已知了. 然后通过墙会被数字分成9块. 然后做数独,这里的数独不是分成9个3*3的小块而是通过墙分成的. 思路: 首先通过数字作出墙. 然后bfs求连通块,dfs也可以.目的是分块. 然后就是dlx数独模板题了. 这里要注意的是如果找到答案2次就说明有多组解了,就应该停止返回了.不然会TLE. 代码: #include"stdio.h" #in

POJ 3074 Sudoku 舞蹈链

#include <cstdio> #include <iostream> #include <algorithm> #include <queue> #include <stack> #include <cstdlib> #include <cmath> #include <set> #include <map> #include <vector> #include <cstri

hdu 4069 舞蹈链

#include <cstdio> #include <iostream> #include <algorithm> #include <vector> #include <map> #include <cstring> #include <queue> using namespace std; const int maxn = 2096; const int maxnode = 10000; int wa[4] = {1

ACM~排列组合&amp;&amp;hdu样例

排列组合是数学中的一个分支,在计算机编程方面也有很多的应用,主要有排列公式和组合公式,错排公式.母函数.Catalan Number(卡特兰数)等. 一.有关组合数学的公式 1.排列公式   P(n,r)=n!/r! 2.组合公式   C(n,r)=n!/(r!*(n-r)!)  C(n,r)=C(n-1,r)+C(n-1,r-1) 3.错排公式   d[1]=0;   d[2]=1; d[n]=(n-1)*(d[n-1]+d[n-2]) 4.卡特兰数 前几项:1, 2, 5, 14, 42,

HDU 2828 舞蹈链可重复覆盖

点击打开链接 题意:给n个灯,每个灯能保持亮的状态的条件给出,最后问能否将所有的灯都保持亮的状态,能的话输出每个开关的状态 思路:明显的舞蹈链可重复覆盖嘛,列为n个灯,然后行为每个开关开还是关,所以行要有2*m行,注意的是在跑舞蹈链的时候,每一个开关只能有开或关的状态,所以我们要判断一下它对应的状态是否走过 #include <vector> #include <stdio.h> #include <string.h> #include <stdlib.h>

HDU 2295 舞蹈链可重复覆盖+二分

点击打开链接 题意:给了n个点和m个圆心,在用不多于k个圆的情况下,使得所有的点被覆盖,最小的圆半径多大 思路:问最小的什么什么那么用二分准没错,那么二分条件是什么呢,就是用不多于K的圆能否将所有点覆盖,覆盖这部分就是裸的舞蹈链的可重复覆盖,行为m个圆,列为n个点,然后求出的最少行小于等于K,则成立,否则不成立 #include <math.h> #include <vector> #include <stdio.h> #include <string.h>

8/2 multi4 E找规律+模拟,空间开小了然后一直WA。。。J爆搜check不严谨WA。。。multi3 G凸包判共线写错数组名???样例太好过.想哭jpg。

multi4 Problem E. Matrix from Arrays 题意:构造一个数组,求子矩阵前缀和. 思路:打表找规律,"发现"L为奇数时循环节为L,为偶数时循环节为2L,求相应循环节的二维前缀和然后加加减减计算一下就好. 虚伪地证明一下循环节:L为奇数时对于第x行/列开始的位置有(x  +  x+L-1)*L/2   ->     (2x+L-1)/2(为整数)*L,因此扫过L行/列也就扫过了L整数倍"(2x+L-1)/2"倍的A[0]~A[L],