首先思考是不是可以直接通过枚举情况求解出来 可以发现是不行的 不存在通式,于是只能采取模拟的方法 问题的关键在于模拟一个组合数的排列情况
这里我给出两种 递归/字典序生成的方法
前者相当好理解 后者更方便且有stl的现成函数使用
代码如下
这里我给出两种 递归/字典序生成的方法
前者相当好理解 后者更方便且有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 阅读



