暑假训练第二周周报
总体学习情况
这周时间大多花在写上周的堆栈的题单了,然后比赛又碰到了一些新的知识点,比如无权二分图的最大匹配,01背包的相似例题,但是感觉数据结构的基础还是得练,遇到一些题还是没办法写对。
知识点模块
1.无权二分图最大匹配
用通俗的话来讲,假如有几个男的和几个女的存在暧昧关系,其中有多个男的和多个女的存在暧昧关系也有多个 女的和多个男的存在暧昧关系,比如喜羊羊和美羊羊、红太狼存在暧昧关系,美羊羊和沸羊羊、喜羊羊存在暧昧关系,等等,让你找最多的配对数,也就是让你找最多的1v1的关系。
struct augment_path {
vector<vector<int> > g;
vector<int> pa; // 匹配
vector<int> pb;
vector<int> vis; // 访问
int n, m; // 两个点集中的顶点数量
int dfn; // 时间戳记
int res; // 匹配数
augment_path(int _n, int _m) : n(_n), m(_m) {
assert(0 <= n && 0 <= m);
pa = vector<int>(n, -1);
pb = vector<int>(m, -1);
vis = vector<int>(n);
g.resize(n);
res = 0;
dfn = 0;
}
void add(int from, int to) {
assert(0 <= from && from < n && 0 <= to && to < m);
g[from].push_back(to);
}
bool dfs(int v) {
vis[v] = dfn;
for (int u : g[v]) {
if (pb[u] == -1) {
pb[u] = v;
pa[v] = u;
return true;
}
}
for (int u : g[v]) {
if (vis[pb[u]] != dfn && dfs(pb[u])) {
pa[v] = u;
pb[u] = v;
return true;
}
}
return false;
}
int solve() {
while (true) {
dfn++;
int cnt = 0;
for (int i = 0; i < n; i++) {
if (pa[i] == -1 && dfs(i)) {
cnt++;
}
}
if (cnt == 0) {
break;
}
res += cnt;
}
return res;
}
};
把点放进去具体实现需要以下几步
augment_path ans(n,n);//初始化这个
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
ans.add(i,j);//根据题意去放点
}
}
cout<<ans.solve()<<endl;
2.单调栈的使用
顾名思义,就是栈里存单调递增或单调递减的数。
具体的作用:可以用来找一个数左边第一个大于或第一个小于该数的数
while(st.size()&&st.top()<x)
{
st.pop();
}
st.push(x);
例题可以参考 区区区间间间
3.初步学习了01背包
模型大概就是,有一个容量为N的背包,有多个物品各自的体积为\(vi\),各自的价值为 \(wi\),然后要求你得出放入的总价值最大是多少。
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1005;
int v[MAXN]; // 体积
int w[MAXN]; // 价值
int f[MAXN][MAXN]; // f[i][j], j体积下前i个物品的最大价值
int main()
{
int n,m; cin>>n>>m;
for(int i=1;i<=n;i++) cin>>v[i]>>w[i];
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(j<v[i]) f[i][j]=f[i-1][j];
else{
f[i][j]=max(f[i-1][j],f[i-1][j-v[i]]+w[i]);
}
}
}
cout<<f[n][m];
}
4.巧用multiset来做一些维护最大值或最小值的题
比如这一题就是用双指针和multiset来找字符串区间最小的字符
B - Reserve or Reverse
#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
typedef pair<int,int> pii;
typedef pair<char,int>pci;
#define x first
#define y second
#define all(v) v.begin(),v.end()
int dx[]={0,1,0,-1};
int dy[]={1,0,-1,0};
signed main()
{
ios::sync_with_stdio(0),cin.tie(0);
int n; cin>>n;
string s; cin>>s;
multiset<char>se;
for(int i=0;i<n;i++) se.insert(s[i]);
int l=0,r=n-1;
while(l<r)
{
//先检查一下s【l】是不是l-r这段区间的最小字母
//如果不是,找一个离r最近的并且最小的字母与之交换
if(s[l]!=*se.begin())
{
while(s[r]!=*se.begin()){//如果不是就从set里删掉,维护区间最小字母
se.erase(se.find(s[r]));//每一次移动都要记得更新区间,达到维护区间最小的目的
r--;
}
swap(s[l],s[r]);
se.erase(se.find(s[l]));
l++;
se.erase(se.find(s[r]));
r--;
}else{
se.erase(se.find(s[l]));
l++;
}
}
cout<<s<<endl;
return 0;
}
最后其实这周还有很多题没补完,因为题单总也是要刷完的,所以只能慢慢去补了。
posted on 2024-07-21 17:34 swj2529411658 阅读(41) 评论(0) 编辑 收藏 举报