- 一 扩散——广度优先搜索
- 二 阶乘约数——数论
- 三 本质上升序列——动态规划
- 四 玩具蛇——DFS
题目链接
注意坐标可能是负数就可以了,因此,我们把初始点整体右移一定距离,然后常规BFS。
#includeusing namespace std; string s11,s22 ,s1 ,s2; int N = 3000; int a[8000][8000]; int times[8000][8000]; typedef pair P; P beg,cur,next,end; queue Q; int dir[4][2] = { {1,0},{0,1},{-1,0},{0,-1}}; int main(){ a[N][N] = 1; a[2020+N][11+N] = 1; a[11+N][14+N] = 1; a[2000+N][2000+N] = 1; beg.first = N;beg.second = N; Q.push(beg); beg.first = 2020+N;beg.second = 11+N; Q.push(beg); beg.first = 11+N;beg.second = 14+N; Q.push(beg); beg.first = 2000+N;beg.second = 2000+N; Q.push(beg); int tx, ty; while(!Q.empty()){ cur= Q.front();Q.pop(); if(times[cur.first][cur.second] == 2020){ break; } for(int i = 0 ; i < 4; ++i){ tx = cur.first + dir[i][0]; ty = cur.second + dir[i][1]; if(a[tx][ty] == 1){ continue; } else{ times[tx][ty] = times[cur.first][cur.second] + 1; a[tx][ty] = 1; next.first = tx; next.second = ty; Q.push(next); } } } int ans = 0; for(int i = 0 ; i < 8000; ++i){ for(int j = 0 ; j < 8000; ++j){ if(a[i][j]){ ans++; } } } cout<
二 阶乘约数——数论 题目链接
思路根据数论知识:任意一个正整数都可以写成若干质数的乘积,X = p1^α1 * p2^ α2 …… * pk^αk
那么约数的个数p = (α1+1)*(α2 +1)*…*(αk +1)
有了上述基础,那么n!的约数个数也就是先把n!转为若干质数的乘积,并统计每一个质数的个数,然后根据公式求得约数个数即可。#includeusing namespace std; #define int long long map m; signed main(){ //统计n个数的若干质数乘积。 for(int i = 2; i <=100;++i){ int t = i; //统计每一个数t的若干质数乘积 for(int j = 2 ; j <= t ;){ if(t % j == 0){ t = t / j; m[j] ++; }else{ j ++; } } } map ::iterator it = m. begin(); //根据公式求得约数。 int ans = 1; for(;it!=m.end();++it){ ans = ans*(it->second+1); } cout< 三 本质上升序列——动态规划 题目链接
思路
据说90%的字符串问题都可以用 动态规划(dp) 解决哦动态规划三大步, 1.设状态表示方程 2.找状态转移方程 3.状态方程初始化
dp 思路:题目要求去重递增子序列的个数,不妨拆开来做,即先求递增子序列的个数,再考虑去重。
1.假设dp[i]表示前i个的递增子序列的个数(通常为题目所求结果即为状态表示方程)
2. 由于是递增子序列,那么 需满足前提 dp[i] > dp[j],有 dp[i] = dp[i] + dp[j]。 显然j < i。
3.因为每一个str[i]是一个递增子序列,那么初始化 dp[i] = 1;现在考虑去重,在第2个中的状态转移方程中,我们只考虑了dp[i] > dp[j]的情形,那么如果dp[i] == dp[j]和dp[i]
- 对于dp[i] < dp[j],不符合题意,continue掉;
- 对于dp[i] == dp[j],说明此时有两个字符是相同的,那么dp[j]与dp[j]前面的子序列组成的情况 和 dp[i]与dp[j]前面子序列组成的情况必然会出现重复统计,例如 a n n,dp[0] = 1 dp[1] = 3 dp[2] = 3 ,这里重复统计了一次an的递增子序列,即a、 n、 an ,所以有dp[i] = dp[i] - dp[j]。
因此,总的状态转移为:
if(str[i] > str[j]){ dp[i] = dp[i] + dp[j]; } else if(str[i] == str[j]){ dp[i] = dp[i] - dp[j]; }#includeusing namespace std; #define int long long set sets; string str; string s; // 共有2的200次方种方案, 铁定超时,所以下面用dp做。 void dfs(int i){ if(i >= str.size()){ sets.insert(s); return; } if(str[i] > s[s.size()-1]){ //可选 s+=str[i]; dfs(i+1); s.erase(s.size()-1); } dfs(i+1); //不选 } int dp[1000]; signed main(){ str = "tocyjkdzcieoiodfpbgcncsrjbhmugdnojjddhllnofawllbhfiadgdcdjstemphmnjihecoapdjjrprrqnhgccevdarufmliqijgihhfgdcmxvicfauachlifhafpdccfseflcdgjncadfclvfmadvrnaaahahndsikzssoywakgnfjjaihtniptwoulxbaeqkqhfwl"; // dfs(0); // cout< dp[i] = 1; //每个本身有一个。 for(int j = 0; j < i; ++j){ if(str[i] > str[j]){ dp[i] = dp[i] + dp[j]; } else if(str[i] == str[j]){ dp[i] = dp[i] - dp[j]; //去重 假如有 a n n ,那么dp[1] = 3, dp[2] = 3 因此是重复统计了一次an的子序列,即a n an } } } int ans = 0; for(int i = 0 ;i < str.size();++i) ans += dp[i]; cout< 四 玩具蛇——DFS 题目链接
确定了一个位置后,下一个位置可能的情况就知道了,这就可以用深度优先搜索来做。题目的意思就是要求1-16依次连续放入方格中的方案数量。#includeusing namespace std; int dir[4][2] = { {0,1}, {1,0},{-1,0},{0,-1}}; int vis[10][10]; int cnt; int k; void dfs(int x, int y){ if(k == 16){ cnt ++; // for(int i = 1; i <= 4; ++i){ // for(int j = 1; j <= 4; ++j){ // cout< int tx = x + dir[i][0]; int ty = y+dir[i][1]; if(tx>=1 &&tx <= 4 && ty >= 1 && ty <= 4 && vis[tx][ty] == 0){ k++; vis[tx][ty] = k; dfs(tx, ty); k--; vis[tx][ty] = 0; } } } int main(){ for(int i = 1; i <= 4; ++i){ for(int j = 1; j <= 4; ++j){ k = 1; vis[i][j] = 1; dfs(i,j); vis[i][j] = 0; } } cout<



