aboyl 题解分享 · 2025/3/3
五子棋对弈(结果填空) - 题解
首先思考是不是可以直接通过枚举情况求解出来 可以发现是不行的 不存在通式,于是只能采取模拟的方法 问题的关键在于模拟一个组合数的排列情况 这里我给出两种 递归/字典序生成的方法 前者相当好理解 后者更方便且有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
yankai 题解分享 · 2024/12/18
五子棋对弈(结果填空) - 题解
暴力枚举所有棋局情况,最终棋局白棋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