题解分享
题解分享简介
五子棋对弈(结果填空) - 题解
首先思考是不是可以直接通过枚举情况求解出来 可以发现是不行的 不存在通式,于是只能采取模拟的方法 问题的关键在于模拟一个组合数的排列情况
这里我给出两种 递归/字典序生成的方法
前者相当好理解 后者更方便且有stl的现成函数使用
代码如下
```
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define pii pair long long
#define endl "\n"
int sy=2000,sm=1,sd=1;
int ey=2024,em=4,ed=13;
int cy,cm,cd;
int nums[10]={13,1,2,3,5,4,4,2,2,2};
int ans=0;
void date() {
cy = sy;
cm = sm;
cd = sd;
int month_day_local[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
while (true) {
// 计算字符串
string s = to_string(cy) + (cm < 10 ? "0" : "") + to_string(cm) + (cd < 10 ? "0" : "") + to_string(cd);
int sum = 0;
for (char ch : s) sum += nums[ch - '0'];
if (sum > 50) ans++;
if (cy == ey && cm == em && cd == ed) break;
// 更新日期
month_day_local[2] = (cy % 400 == 0 || (cy % 4 == 0 && cy % 100 != 0)) ? 29 : 28;
cd++;
if (cd > month_day_local[cm]) { cm++; cd = 1; }
if (cm > 12) { cm = 1; cy++; }
}
}
int zh(int n, int m) {
if (m > n - m) m = n - m; // C(n, m) = C(n, n-m),减少乘法次数
int ans = 1;
// c_n_k+1=c_n_k*(n-k/j+1) 因此必然是整数
for (int i = 0; i < m; i++) {
ans *= (n - i);
ans /= (i + 1); //必须分子先乘大的 分母除以小的 这样优化不会导致出问题
}
return ans;
}
int check(vector<int>& v) {
// 直接用 1D 数组访问,不用构造 2D 数组
int flag_r = 1, flag_c = 1, flag_x1 = 1, flag_x2 = 1;
for (int i = 0; i < 5; i++) {
int t = v[i * 5];
if (t == v[i * 5 + 1] && t == v[i * 5 + 2] && t == v[i * 5 + 3] && t == v[i * 5 + 4]) flag_r = 0;
t = v[i];
if (t == v[i + 5] && t == v[i + 10] && t == v[i + 15] && t == v[i + 20]) flag_c = 0;
}
int t = v[0];
if (t == v[6] && t == v[12] && t == v[18] && t == v[24]) flag_x1 = 0;
t = v[4];
if (t == v[8] && t == v[12] && t == v[16] && t == v[20]) flag_x2 = 0;
return (flag_r && flag_c && flag_x1 && flag_x2);
}
void next_com(vector<int>& v,int start,int cnt){
//通过递归的思想 此时我们的思路就是 从后去想 尽量不重复
if(cnt==0){
//此时达到了一种排序 终止条件 选到了对应数量的
//此时我们的v 是一种排序 直接映射到棋盘上 检测是否可以
if(check(v)) ans++;
// for(auto it:v) cout<<it;
// cout<<endl;
return ;
}
int n=v.size();
for(int i=start;i<=n-cnt;i++){
//随机选择一个
v[i]=1;
next_com(v,i+1,cnt-1);
v[i]=0;//还原
}
}
void solve(){
//5*5的棋局共25 终局不同
//题目要求解平局的情况 棋盘下满 那就是 13/12 白方13 黑方12 的棋盘情况
//一共就5+5+2 12种连成5颗棋子的情况 平局那一定是总情况-白方胜 不可能是黑方胜
//白方胜就是 (13,12) 最后一子
//不可能这两个情况里都有 经过分析可以知道 不同的白方胜的情况 黑子可以走的总数是不一样的 因此我们只能通过模拟来进行
//黑子 白子 都不能取胜 因此我们需要模拟组合数的问题
//这里有两种组合顺序的遍历 一种是递归(需要占空间) 另一种则是借助字典序生成组合 无需空间复杂度
int n,k;
n=25;
k=13;
vector<int> v(n,0);
//这种排列模拟 一定要头脑清晰去判断逻辑
//先给一个最小的 从小到大进行 000...111
for(int i=n-k;i<n;i++) v[i]=1;
//next_com(v,0,k);
// while(1){
// int i=n-2;
// while(i>=0&&v[i]>=v[i+1]) i--;
// if(i>=0){
// int j=n-1;
// while(j>=0&&v[j]<=v[i]) j--;
// swap(v[i],v[j]);
// //要reverse的
// reverse(v.begin()+i+1,v.end());
// if(check(v)) ans++;
// } else{
// //已经是最大的了
// break;
// }
// }
//还有更好的原地借助字典序生成 也可以用现成的函数
while(1){
if(check(v)) ans++;
if(!next_permutation(v.begin(),v.end())) break;
}
cout<<ans<<endl;
}
signed main() {
int t = 1;
// cin>>t;
while (t--) {
solve();
}
}
```
查看全文
0
0
1
4
五子棋对弈(结果填空) - 题解
暴力枚举所有棋局情况,最终棋局白棋13颗,黑棋12颗。
check函数判断是否有人获胜,因为棋盘只有55,所以只需要判断每一行、每一列、两条对角线是否有连续的相同棋子即可。
dfs函数:当前枚举x,y位置,还有left颗白棋没填。
边界:当枚举到x==6时,且用完所有白棋时,check棋局情况。dfs过程没有提前剪枝使得最终left不为0的情况,因为这个dfs是2的25次方数量级,不会爆栈orTLE。
```cpp
#include<bits/stdc++.h>
#define endl '\n'
using namespace std;
using ll = long long;
using pii = pair<int,int>;
using pll = pair<ll,ll>;
int ans = 0;
int g[6][6];
bool check(){
for(int i=1;i<=5;i++){
bool flag = true;
for(int j=2;j<=5;j++){
if(g[i][j]!= g[i][j-1]) flag = false;
}
if(flag) return false;
flag = true;
for(int j=2;j<=5;j++){
if(g[j][i]!=g[j-1][i]) flag = false;
}
if(flag) return false;
}
bool flag = true;
for(int i=2;i<=5;i++){
if(g[i][i] != g[i-1][i-1]) flag = false;
}
if(flag) return false;
flag = true;
for(int i=2;i<=5;i++){
if(g[i][6-i] != g[i-1][6-i+1]) flag= false;
}
if(flag) return false;
return true;
}
void dfs(int x,int y,int left){
if(x>5||y>5){
if(left==0){
if(check()) ans++;
}
return;
}
auto get_nxt=[&](int x,int y)->pii{
y++;
if(y>5) x++,y = 1;
return {x,y};
};
auto [nx,ny] = get_nxt(x,y);
if(left!=0){
g[x][y] = 1;
dfs(nx,ny,left-1);
g[x][y] = 0;
}
dfs(nx,ny,left);
}
void solve(){
dfs(1,1,13);
cout<<ans<<endl;
}
int main(){
ifstream test_file("0in.txt");
if (test_file) {
freopen("0in.txt", "r", stdin);
freopen("0output.txt", "w", stdout);
}
std::ios::sync_with_stdio(0);std::cout.tie(0);std::cin.tie(0);
int T = 1;
#ifdef MULTI_TEST
cin>>T;
#endif
while(T--){
solve();
}
return 0;
}
```
查看全文
0
0
0
4



