牛客算法周周练7 ACDE
闲扯下:A,E题解...写在最后,然后B....不会,不过好像大不了硬写一个搜索好像也能过,题都没咋读懂
先写D题,C当时没有dp出来
D
D题其实算是求割边数量的板子题,什么是割边呢?即比如我们把一个图中一条边去掉,就会变成两个图,但是如果我们要去掉的那条边在自环上,就不存在割边
如果知道割边的数量,那么答案即总边数减去割边数,所以就是一个板子题.........
然后这个割边咋求具体看代码
时间复杂度:
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N = 1e5 + 50; int low[N], num[N], dfn; //dfn记录递归深度,用于给num赋值 bool iscut[N]; vector<int> G[N]; int ans; //存图 void dfs(int u, int fu) //u的父节点是fu { low[u] = num[u] = ++dfn; //随着深度增加,low和num增大 int child = 0; for (int i = 0; i < G[u].size(); i++) //处理u的所有邻居 { int v = G[u][i]; if (!num[v]) //没被访问过 { child++; dfs(v, u); low[u] = min(low[u], low[v]); //用后代返回值更新low if (low[v] > num[u]) ans++; //记录割边数量 } else if (num[v] < num[u] && v != fu) //处理回退边 low[u] = min(low[u], num[v]); } } int main() { int n, m; cin >> n >> m; //初始化 memset(low, 0, sizeof(low)); memset(num, 0, sizeof(num)); memset(iscut, false, sizeof(iscut)); for (int i = 0; i < N; i++) G[i].clear(); dfn = 0; for (int i = 0; i < m; i++) { int x, y; cin >> x >> y; G[x].push_back(y); G[y].push_back(x); } dfs(1, -1); cout << m - ans << endl; return 0; }
C
这没啥说的dp
这个就不献丑了,转载了一下当时牛客官方给的题解
#include<bits/stdc++.h> using namespace std; int dp[2][405][405]; char s[406]; int main() { int n,k; scanf("%d%d",&n,&k); scanf("%s",s+1); memset(dp,0x3f,sizeof dp); dp[0][0][0]=0; for(int i=1;i<=n;i++){ memset(dp[i%2],0x3f,sizeof dp[i%2]); for(int j=i;j>=0;j--){//总天数 for(int l=0;l<=j;l++){//连续工作天数 dp[i%2][j][0]=min(dp[i%2][j][0],dp[(i+1)%2][j][l]); if(s[i]=='1'&&l){ dp[i%2][j][l]=min(dp[i%2][j][l],dp[(i+1)%2][j-1][l-1]+l); } } } } int ans=0; for(int i=0;i<=n;i++){ for(int j=0;j<=i;j++){ if(dp[n%2][i][j]<=k){ ans=max(ans,i); } } } cout<<ans<<endl; }
A,E
然后再说下A,E
先说E题比较指数大小可以转换成比较对数大小
A题排序,比如起点在左下角,那么假设我们先走到最右上的那个点,中间能走到的走一下,然后剩下的点,在回起点的时候,再走