CF293B 方格(带技巧的搜索)

图片描述

solution:

首先我们根据一条路径上不能有两个相同颜色的格子可以得出:
对于两个格子 $ (x_1 , y_1 ) $ 和 $ (x_2 , y_2 ) $ 必须满足:

$ x_1<x_2 and y_1>y_2 $

$ x_1>x_2 and y_1<y_2 $

所以我们可以据此剪枝,但直接暴搜肯定会超时,我们肯定还有技巧:

  1. 根据上面的剪枝我们发现将表格以(1,1) -> (n,n) -> (1,2) -> (2,1) -> (n,n-1) -> (n-1,n). . .的顺序枚举速度会快很多

  2. 现在,我们把初始棋盘中没有出现过的颜色称作自由颜色。如果我们有两个自由颜色: 1 和 2 .假设我们找到了一个可行的最终棋盘,然后把所有的 1 换成 2 ,所有的 2 换成 1 。容易发现得到的棋盘依然是可行的。
    我们把自由颜色排序(随便怎么排),如果我们当前没有用过第 i 个自由颜色,那么我们就不准碰第 i+1 个自由颜色。到最后计算结果的时候,如果我们用了 x 个自由颜色,而总共有 y 个自由颜色,那么这个局面对答案的贡献也就是 y 个数中去取 x 个组成有序排列的数目。

code:

#include<iostream>
#include<cstdio>
#include<iomanip>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<ctime>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>

#define ll long long
#define db double
#define inf 0x7fffffff
#define rg register int
#define mod 1000000007
#define end {puts("0");return 0;}

using namespace std;

struct su{
    int x,y;
}b[13],c[13],d[11][11];

ll ans;
int n,m,l,k,ti,top,sss;
int se[11],to[11];
int tot[11];
int P[11];
int a[10][10];
int ss[10][10];
bool s[10][10];

inline int qr(){
    char ch;
    while((ch=getchar())<'0'||ch>'9');
    int res=ch^48;
    while((ch=getchar())>='0'&&ch<='9')
        res=res*10+(ch^48);
    return res;
}

inline void add(int t,int x,int y){
    d[t][++tot[t]].x=x;
    d[t][tot[t]].y=y;
}

inline bool check(int i,int x,int y){
    for(rg j=1,p,q;j<=tot[i];++j){
        p=d[i][j].x;q=d[i][j].y;
        if(x>=p&&y>=q)return 0;
        if(x<=p&&y<=q)return 0;
    }return 1;
}

inline void dfs(int t){
    if(t>n*m){
        ans+=P[to[0]+sss-k];
        return ;
    }
    rg x=b[t].x,y=b[t].y;
    if(s[x][y]){dfs(t+1);return ;}
    for(rg i=1;i<=to[0];++i){
        if(check(i,x,y)){
            add(i,x,y);
            ss[x][y]=i;
            dfs(t+1);
            --tot[i];
        }
    }
    if(to[0]==k)return ;
    add(++to[0],x,y);
    ss[x][y]=to[0];
    dfs(t+1);
    tot[to[0]]=0;--to[0];
    return ;
}

inline void bfs(){
    for(rg o=1,i=0,j=1;o<=l;++o){
        c[o].x=((i==n)?i:++i);
        c[o].y=((i>=n)?j++:j);
    }
    for(rg o=0,r,i,j;o<l;++o){
        r=o&1?l-o/2:o/2+1;
        i=c[r].x;j=c[r].y;
        for(;i&&j<=m;--i,++j)
            b[++top].x=i,b[top].y=j;
    }
}

int main(){
    //freopen("board.in","r",stdin);
    //freopen("board.out","w",stdout);
    n=qr(),m=qr(),k=qr();
    if((l=n+m-1)>k) end;
    for(rg i=1;i<=n;++i)
        for(rg j=1;j<=m;++j){
            ti=a[i][j]=qr();
            if(ti){
                s[i][j]=1;
                if(se[ti]){
                    ti=se[ti];
                    ss[i][j]=ti;
                }
                else{
                    ti=se[ti]=++to[0];
                    to[ti]=a[i][j];
                    ss[i][j]=ti;
                }
				if(!check(ti,i,j)){
					puts("0");
					return 0;
				}
				add(ti,i,j);
            }
        }
    sss=k-to[0];P[0]=1;
    for(rg i=0;i<sss;++i)
        P[i+1]=P[i]*(sss-i);
	if(l==k){
		printf("%d\n",P[sss]);
		return 0;
	}
    top=0; bfs(); dfs(1);
    printf("%lld\n",ans%mod);
    return 0;
}

posted @ 2019-01-23 08:15  一只不咕鸟  阅读(207)  评论(0编辑  收藏  举报