Codeforces 293B
题目链接:http://acm.hust.edu.cn/vjudge/problem/38379
题目大意:
给出一个n*m的矩阵,其中一些格子填了数,一些格子没有。现要求将未填数的格子填上数字,使得矩阵从左上到右下(不允许向左或上走)的任意一条路径上没有两个格子数字相同,数字范围为1~K。 1<=n,m<=1000,1<=k<=10
分析:
首先一看,在(n+m-1)大于K时必定无解,这样就把n,m范围缩小到了10以内。
我们考虑搜索解决。但是纯暴搜时间不够,可以用两个剪枝优化:
(1)可行性剪枝,如果在当前格子填数时,剩下的颜色已经不够用则直接回溯。
(2)对称性剪枝:例如我们当前填到了某个格子,我们记录一下整个矩阵已使用的颜色,例如3,5都还没用,那么这个格子填上3或5,两者最终算出的方案数是相同的,这样我们就可以只计算3的方案数,5的直接加上3的就可以了。
代码:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#define rep(i,x,y) for (int i=x;i<=y;i++)
#define dep(i,y,x) for (int i=y;i>=x;i--)
#define mp(x,y) make_pair(x,y)
#define bit(x,d) ((((x)&(1<<(d)))==0)?0:1)
using namespace std;
typedef long long LL;
const int maxn=10+2;
const LL MOD=1000000000+7;
int F[maxn][maxn],vis[maxn],a[maxn][maxn],n,m,k,x;
LL ans;
void search(int x,int y)
{
if (x==(n+1))
{
ans++;
if (ans==MOD) ans=0;
return;
}
F[x][y]=F[x-1][y]|F[x][y-1]; //位运算计算当前格子已使用颜色
int p=1,q=k,c=0;
rep(i,1,k) if (bit(F[x][y],i-1)) c++;
if (((n-x)+(m-y)+1)>(k-c)) return; //可行性剪枝
LL sum=-1,pre;
if (a[x][y]>0) p=q=a[x][y];
rep(i,p,q)
if (!(bit(F[x][y],i-1)))
{
if (!vis[i])
{
if (sum>=0) //对称性剪枝
{
ans+=sum;
if (ans>MOD) ans-=MOD;
continue;
}
pre=ans;
}
F[x][y]^=(1<<(i-1)),vis[i]++;
if (y==m) search(x+1,1); else search(x,y+1);
F[x][y]^=(1<<(i-1)),vis[i]--;
if (!vis[i])
{
sum=(ans-pre)%MOD;
}
}
}
int main()
{
scanf("%d%d%d",&n,&m,&k);
if ((n+m-1)>k) {printf("%d\n",0);return 0;} //特判
memset(F,0,sizeof(F));
memset(vis,0,sizeof(vis));
rep(i,1,n)
rep(j,1,m)
{
scanf("%d",&a[i][j]);
if (a[i][j]>0) vis[a[i][j]]++; //记录颜色出现数
}
ans=0;
search(1,1);
printf("%I64d\n",ans);
return 0;
}
另一种做法,在没有限制的图上搜索,最终用排列数来计算对称解。
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#define rep(i,x,y) for (int i=x;i<=y;i++)
#define dep(i,y,x) for (int i=y;i>=x;i--)
#define bit(x,d) ((((x)&(1<<(d)))==0)?0:1)
using namespace std;
typedef long long LL;
const int maxn=10+2,MOD=1000000000+7;
int n,m,K,a[maxn][maxn],p[maxn],F[maxn][maxn],num[maxn][maxn];
bool pused[maxn],aused[maxn];
LL ans;
void check()
{
memset(p,0,sizeof(p));
memset(pused,0,sizeof(pused));
memset(aused,0,sizeof(aused));
int color=0,Kc=K;
rep(i,1,K) if (bit(F[n][m],i-1)) color++;
rep(i,1,n)
rep(j,1,m)
if (a[i][j])
{
if ((pused[num[i][j]])||(aused[a[i][j]])) return;
p[num[i][j]]=a[i][j];
pused[num[i][j]]=1,aused[a[i][j]]=1;
Kc--;
}
rep(i,1,K) if (pused[i]) color--;
LL k=1;
dep(i,Kc,Kc-color+1) k=(k*i)%MOD;
ans+=k;
if (ans>MOD) ans-=MOD;
}
void search(int x,int y,int maxc)
{
if (x==(n+1)) {check();return;}
F[x][y]=F[x-1][y]|F[x][y-1];
rep(i,1,maxc)
if (!bit(F[x][y],i-1))
{
num[x][y]=i,F[x][y]^=(1<<(i-1));
if (y==m) search(x+1,1,min(K,max(i+1,maxc))); else search(x,y+1,min(K,max(i+1,maxc)));
num[x][y]=0,F[x][y]^=(1<<(i-1));
}
}
int main()
{
scanf("%d%d%d",&n,&m,&K);
if ((n+m-1)>K) {printf("%d\n",0);return 0;}
rep(i,1,n) rep(j,1,m) scanf("%d",&a[i][j]);
search(1,1,1);
printf("%I64d\n",ans);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步