[Acwing面向模型编程]dfs
题目1:AcWing 1118. 分成互质组
分析:
枚举每个数,他既可以放到当前已经有的箱子里,也可以新开一个箱子。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;//三年竞赛一场空,不开long long见祖宗
//typedef __int128 lll;
#define print(i) cout << "debug: " << i << endsl
#define close() ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
#define mem(a, b) memset(a, b, sizeof(a))
#define pb(a) push_back(a)
#define x first
#define y second
typedef pair<int, int> pii;
const ll mod = 1e9 + 7;
const int maxn = 1e5 + 10;
const int inf = 0x3f3f3f3f;
int n;
int a[20];
int group[20][20], cnt[20];
int ans = 10;
bool judge(int now, int val)
{
for(int i = 1; i <= cnt[now]; i++)
if(__gcd(group[now][i], val) > 1)
return false;
return true;
}
void dfs(int id, int num)
{
if(num >= ans) return;
if(id == n + 1)
{
ans = min(ans, num);
return;
}
for(int i = 1; i <= num; i++)
{
if(judge(i, a[id]))
{
group[i][++cnt[i]] = a[id];
dfs(id + 1, num);
cnt[i]--;
}
}
cnt[num + 1] = 1;
group[num + 1][cnt[num + 1]] = a[id];
dfs(id + 1, num + 1);
cnt[num + 1] = 0;
}
int main()
{
cin >> n;
for(int i = 1; i <= n; i++) cin >> a[i];
dfs(1, 0);
cout << ans << endl;
}
题目2:165. 小猫爬山
分析:做法跟上题一样
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;//三年竞赛一场空,不开long long见祖宗
//typedef __int128 lll;
#define print(i) cout << "debug: " << i << endsl
#define close() ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
#define mem(a, b) memset(a, b, sizeof(a))
#define pb(a) push_back(a)
#define x first
#define y second
typedef pair<int, int> pii;
const ll mod = 1e9 + 7;
const int maxn = 1e5 + 10;
const int inf = 0x3f3f3f3f;
int n, m;
int a[20];
int group[20];
int ans = 20;
void dfs(int id, int num)
{
if(num >= ans) return;
if(id == n + 1)
{
ans = min(ans, num);
return;
}
for(int i = 1; i <= num; i++)
{
if(group[i] + a[id] <= m)
{
group[i] += a[id];
dfs(id + 1, num);
group[i] -= a[id];
}
}
group[num + 1] = a[id];
dfs(id + 1, num + 1);
group[num + 1] = 0;
}
int main()
{
cin >> n >> m;
for(int i = 1; i <= n; i++) cin >> a[i];
dfs(1, 0);
cout << ans << endl;
}
题目3:AcWing 166. 数独
分析:
这个题写起来比较麻烦,这里只说一下思想吧,实现见代码
我们搜索的顺序是:先搜可选数目最小的格子
我们用二进制存储每行每列每个3*3的状态。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;//三年竞赛一场空,不开long long见祖宗
//typedef __int128 lll;
#define print(i) cout << "debug: " << i << endsl
#define close() ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
#define mem(a, b) memset(a, b, sizeof(a))
#define pb(a) push_back(a)
#define x first
#define y second
typedef pair<int, int> pii;
const ll mod = 1e9 + 7;
const int maxn = 1e5 + 10;
const int inf = 0x3f3f3f3f;
const int N = 9;
char s[maxn];
int col[N], rol[N];
int cube[3][3];
int ones[1 << N], ma[1 << N];
int lowbit(int x)
{
return x & -x;
}
void make()
{
for(int i = 0; i < N; i++) ma[1 << i] = i;
for(int i = 0; i < 1 << N; i++)
{
int state = i;
while(state)
ones[i]++, state -= lowbit(state);
}
}
int get(int x, int y)
{
return rol[x] & col[y] & cube[x / 3][y / 3];
}
void init()
{
for(int i = 0; i < N; i++) col[i] = rol[i] = (1 << N) - 1;
for(int i = 0; i < 3; i++)
for(int j = 0; j < 3; j++)
cube[i][j] = (1 << N) - 1;
}
void draw(int x, int y, int t, int add)
{
if(add) s[x * N + y] = t + '1';
else s[x * N + y] = '.';
int val = 1 << t;
if(!add) val = -val;
rol[x] -= val, col[y] -= val;
cube[x / 3][y / 3] -= val;
}
bool dfs(int cnt)
{
if(!cnt) return true;
int minn = 10, mini, minj;
for(int i = 0; i < N; i++)
for(int j = 0; j < N; j++)
{
if(s[i * N + j] == '.')
{
int state = get(i, j);
if(ones[state] < minn)
minn = ones[state], mini = i, minj = j;
}
}
int state = get(mini, minj);
for(int i = state; i; i -= lowbit(i))
{
int t = ma[lowbit(i)];
draw(mini, minj, t, true);
if(dfs(cnt - 1)) return true;
draw(mini, minj, t, false);
}
return false;
}
int main()
{
make();
while(cin >> s && s[0] != 'e')
{
int cnt = 0;
init();
for(int i = 0, k = 0; i < N; i++)
for(int j = 0; j < N; j++, k++)
{
if(s[k] != '.')
draw(i, j, s[k] - '1', true);
else cnt++;
}
dfs(cnt);
cout << s << endl;
}
}
题目4:167. 木棒
分析:
3个剪枝:
- 长度递增枚举
- 跳过长度相等的木棒
- 本轮第一个或者最后一个木棒失败了,则本次枚举一定失败。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;//三年竞赛一场空,不开long long见祖宗
//typedef __int128 lll;
#define print(i) cout << "debug: " << i << endsl
#define close() ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
#define mem(a, b) memset(a, b, sizeof(a))
#define pb(a) push_back(a)
#define x first
#define y second
typedef pair<int, int> pii;
const ll mod = 1e9 + 7;
const int maxn = 1e5 + 10;
const int inf = 0x3f3f3f3f;
int n;
int a[maxn], vis[maxn];
int sum;
int len;
bool dfs(int nownum, int nowlen, int pos)
{
if(nownum * len == sum) return true;
if(nowlen == len) return dfs(nownum + 1, 0, 1);
for(int i = pos; i <= n; i++)
{
if(vis[i] || nowlen + a[i] > len) continue;
vis[i] = 1;
if(dfs(nownum, nowlen + a[i], pos + 1)) return true;
vis[i] = 0;
if(nowlen == 0 || nowlen + a[i] == len) return false;
int j = i;
while(j <= n && a[j] == a[i]) j++;
i = j - 1;
}
return false;
}
int main()
{
while(cin >> n && n)
{
sum = 0;
mem(vis, 0);
for(int i = 1; i <= n; i++) cin >> a[i], sum += a[i];
sort(a + 1, a + 1 + n, [&](int a, int b){
return a > b;
});
for(len = 1; ; len++)
if(sum % len == 0 && dfs(0, 0, 1))
{
cout << len << endl;
break;
}
}
}
题目5:168. 生日蛋糕
分析:
具体分析见acwing算法提高课…
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;//三年竞赛一场空,不开long long见祖宗
//typedef __int128 lll;
#define print(i) cout << "debug: " << i << endsl
#define close() ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
#define mem(a, b) memset(a, b, sizeof(a))
#define pb(a) push_back(a)
#define x first
#define y second
typedef pair<int, int> pii;
const ll mod = 1e9 + 7;
const int maxn = 1e5 + 10;
const int inf = 0x3f3f3f3f;
int n, m;
int minv[maxn], mins[maxn];
int nowr[maxn], nowh[maxn];
int ans = inf;
void dfs(int nowlayer, int nowv, int nows)
{
if(nowv + minv[nowlayer] > n) return; //可行性剪枝
if(nows + mins[nowlayer] >= ans) return; //最优化剪枝
if(nows + 2 * (n - nowv) / nowr[nowlayer + 1] >= ans) return; //最优化剪枝(关键)
if(nowlayer == 0)
{
if(nowv == n) ans = nows;
return;
}
for(int r = min(nowr[nowlayer + 1] - 1, (int)sqrt(n - nowv)); r >= nowlayer; r--)
for(int h = min(nowh[nowlayer + 1] - 1, (n - nowv) / r / r); h >= nowlayer; h--)
{
nowr[nowlayer] = r, nowh[nowlayer] = h;
int add = 0;
if(nowlayer == m) add = r * r;
dfs(nowlayer - 1, nowv + r * r * h, nows + 2 * r * h + add);
}
}
int main()
{
cin >> n >> m;
for(int i = 1; i <= m; i++)
minv[i] = minv[i - 1] + i * i * i, mins[i] = mins[i - 1] + 2 * i * i;
nowr[m + 1] = nowh[m + 1] = inf;
dfs(m, 0, 0);
if(ans == inf) ans = 0;
cout << ans << endl;
}