Problem
初始有 M 个联通的格子 (r, c)
(当两个格子有边重合即视为联通)。给定 1~N 的数字,需要找到在每个格子中填充一个数字,且同行或同列不能有相同数字的前提下,求和|差|积|商(题目将提前指出要求的操作)恰好为 t 。
限制条件
4≤N≤9
2≤m≤10
0<t
1≤r,c≤n
当求差或商时,m 必定为 2 .
解题思路
暴力搜索 + 剪枝。
剪枝策略:
-
O(1)
判断当前格子能否取到数字
i
,为否直接return
. - 判断当前结果与目标结果的预期,无法达到目标结果或以及超过预期结果直接
return
。
暴力的结果在 Gym 100825
中用时 951 ms / 1000 ms
。:smile: 刚好。
代码
#include<bits/stdc++.h>
using namespace std;
int n, m, t, ans, x[10], y[10], ux[10][10], uy[10][10];
long long mxmul[11];
char op;
void dfsadd(int idx, int sum) {
if(sum >= t || (t-sum) > (m-idx)*n || (t-sum) < (m-idx)) return;
if(idx == m-1) {
sum = t - sum;
if(!ux[ x[idx] ][sum] && !uy[ y[idx] ][sum]) ans++;
return;
}
for(int i=1;i<=n;i++)
{
if(ux[ x[idx] ][i] || uy[ y[idx] ][i]) continue;
ux[ x[idx] ][i] = uy[ y[idx] ][i] = 1;
dfsadd(idx+1, sum+i);
ux[ x[idx] ][i] = uy[ y[idx] ][i] = 0;
}
}
void dfsmul(int idx, int sum) {
if(sum > t || t%sum || t/sum > mxmul[m-idx]) return;
if(idx == m-1) {
sum = t / sum;
if(!ux[ x[idx] ][sum] && !uy[ y[idx] ][sum]) ans++;
return;
}
for(int i=1;i<=n;i++)
{
if(ux[ x[idx] ][i] || uy[ y[idx] ][i]) continue;
ux[ x[idx] ][i] = uy[ y[idx] ][i] = 1;
dfsmul(idx+1, sum*i);
ux[ x[idx] ][i] = uy[ y[idx] ][i] = 0;
}
}
int main()
{
scanf("%d %d %d %c", &n, &m, &t, &op);
for(int i=0;i<m;i++)
scanf("%d %d", &x[i], &y[i]);
if(op == '-') {
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(i==j) continue;
else if(abs(i-j) == t) ans++;
} else if(op == '/') {
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++)
if(j%i==0 && j/i==t) ans+=2;
} else if(op == '+') {
dfsadd(0, 0);
} else {
mxmul[0] = 1;
for(int i=1;i<=m;i++)
mxmul[i] = mxmul[i-1] * n;
dfsmul(0, 1);
}
printf("%d\n", ans);
}