笔记
Day 1
The First Class
蒟蒻太蒟了,所以前面没记笔记。
前面笔记推荐czh的:https://www.cnblogs.com/CheZiHe929/p/17538291.html
四.栈(stack)
核心函数同queue,除front变top。
```cpp
求区间最大值
int main(){
cin>>n>>k;
for(int i=1;i<=n;i++){
cin>>a[i];
}
for(int i=1;i<=n-k+1;i++){
int minv=a[i],maxv=a[i];
for(int j=0;j<=k;i++){//枚举区间左端点
minv=min(minv,a[i+j]);
maxv=max(maxv,a[i+j]);
}
cout<<maxv-minv<<'\n';
}
return 0;
}
五。单调队列

对,单调队列的特性就是这四个zhx写的字。(zhx:是笔的问题,我的字很好看的)
求区间最小值
int a[1919810],n,k;
struct queueue{
int z[1919810]={0};
int head=1;
int tail=0;
void push(int x)
while(head<=tail&&a[x]<=a[z[tail]])tail--;
a[++tail]=x;
}
void pop(){
head++;
}
int top(){
return z[head];
}
int back(){
return z[tail];
}
int size(){
return tail-head+1;
}
};
queueue q;
int main(){
cin>>n>>k;
for(int i=1;i<=n;i++){
cin>>a[i];
}
for(int i=1;i<=k;i++){
q.push(i);
}
cout<<q.top()<<endl;
for(int i=2;i<=n-k+1;i++){
q.push(i+k-1);//右边多一个数
if(q.top()==i-1)q.pop();//左边扔一个数
cout<<a[q.top()]<<endl;//第i个区间的答案
}
return 0;
}
B3616、3614、P1886例题
六、优先队列(堆,priority_queue)

大根堆求最大值,小根堆求最小值。
大根堆:priority_queue<int>q;(引用queue库)
小根堆:priority_queue<int,vector<int>,greater<int> >q;(引用queue,functional,vector库)
#include<queue>
#include<functional>
#include<vector>
#include<iostream>
using namespace std;
priority_queue<int,vector<int>,greater<int> >heap;
int main(){
heap.push(233);//向堆里扔一个数,O(logn)
heap.pop();//扔掉最小值,O(logn)
heap.top();//询问最大值 O(1)
heap.size();//询问堆的大小 O(1)
return 0;
}
log过程:


《有点长》
我们要用二叉树来实现堆。
二叉树就是一个节点上有一个左儿子和一个右儿子(子节点)。

父节点的值不能小于子节点。
int main(){
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=n;i++){
priority_queue<int>heap_l;
priority_queue<int,vector<int>,greater<int> >heap_r;
heap_l.push(a[l]);
cout<<l~l的中位数为a[l]<<'\n';
if(a[r]>median)heap_r.push(a[r]);
}
return 0;
}
手写queue
struct heap{
int n;
int top(){//最大值
return a[1];
}
int size(){//大小
return n;
}
void push(int x){//加入一个数
n++;
a[n]=x;
int p=n;
while(p!=1){
int f=p/2;
if(a[f]<a[p]){
swap(a[f],a[p]);
p=f;
}
else break;
}
}
void pop(){//删除最大值
a[1]=a[n];
n--;
int p=1;
while(p*2<=n){
int pp=p*2;//左儿子
if(pp+1<=n && a[pp+1]>a[pp])pp=pp+1;//pp指向更大的
if(a[p]<a[pp]){
swap(a[p],a[pp]);
p=pp;
}
else break;
}
}
七.映射(map)
#include<map>
using namespace std;
map<int,int>a;//下标类型
//map<node,node>a;(重载运算符)
//map<string,int>a;(a["kkksc03"]=1)
int main(){
a[1]=2;//log
a[2147483647]=0;//log
a[-2333]=0;//log
return 0;
}
The second class
算法篇
库:algorithm
一.函数
//对单体的算法
min(a,b);//求最小值
max(a,b);//求最大值
swap(a,b;)//交换两个变量的数值
min(a,min(b,min(c,min(d,e)))//大min套小min(max也可以)
// 要求数据类型一致
//对数组的算法
sort(a+1,a+n+1);//把a[1]~a[n]从小到大排序
quick_sort(a+1,a+n+1);//快排
merge_sort(a+1,a+n+1);//归并
heap_sort(a+1,a+n+1);//堆
sort(a+1,a+n+1,cmp);//自定义
bool cmp(int a,int b){
return a>b;
}
reverse(a+1,a+n+1)//翻转a[1]-a[n]
unique(a+1,a+n+1);//把a[1]-a[n]去重
//如果去重后有x个数,会返回a+x+1
random_shuffle(a+1,a+n+1);//把a[1]~a[n]随机打乱
二.归并排序

void merge_sort(int l,int r){//对a[l]~a[r]排序
if(l==r)return;
int m=(l+r)/2;
merge_sort(1,m);//左部分排序
merge_sort(m+1,r);//右部分排序
int pl=l;//左边第一个数的下标
int pr=m+1;//右边第一个数的下标
for(int i=l;i<=r;i++){
if(pl>m)b[i]=a[pr],pr++;
else if(pr>r)b[i]=a[pl],pl++;
if(a[pl]<a[pr])b[i]=a[pl],pl++;
else b[i]=a[pr],pr++;
}
for(int i=l;i<=r;i++)a[i]=b[i];
}
int main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
}
merge_sort(1,n);
for(int i=1;i<=n;i++){
cout<<a[i];
}
return 0;
}
思想是分治。
O(nlogn)
三.逆序对
和归并排序差不多

三种情况:在左,在右,一半左一半右
long long merge_sort(int l,int r){//对a[l]~a[r]排序
if(l==r)return 0;
int m=(l+r)/2;
ans+=merge_sort(1,m);//左部分排序
ans+=merge_sort(m+1,r);//右部分排序
int pl=l;//左边第一个数的下标
int pr=m+1;//右边第一个数的下标
for(int i=l;i<=r;i++){
if(pl>m)b[i]=a[pr],pr++;
else if(pr>r)b[i]=a[pl],pl++;
if(a[pl]<a[pr])b[i]=a[pl],pl++;
else b[i]=a[pr],pr++,ans+=m-pl+1;
}
for(int i=l;i<=r;i++)a[i]=b[i];
return ans;
}
int main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
}
long long ans=merge_sort(1,n);
for(int i=1;i<=n;i++){
cout<<ans;
}
return 0;
}
四.前缀和
int main(){
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=n;i++)sum[i]=sum[i-1]+a[i];
cin>>m;
for(int i=1;i<=m;i++){
int l,r;
cin>>l>>r;
cout<<sum[r]-sum[l-1];
putchar('\n');
}
}
五.差分

前缀和从l开始都要改掉
把l~r加v,r+1-v。

int main(){
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=n;i++)sum[i]=sum[i-1]+a[i];
cin>>m;
for(int i=1;i<=m;i++){
int l,r,v;
cin>>l>>r>>v;
sum[l]+=v;
sum[r+1]-=v;
}
for(int i=1;i<=n;i++){
sum[i]+=sum[i-1];
}
for(int i=1;i<=n;i++){
cout<<a[i]+sum[i];
putchar('\n');
}
}
六.I/O
freopen("xxx.in","r",stdin);//文件in开启
freopen("xxx.out","w",stdout)//文件out开启;
fclose(stdin);//文件in关闭
fclose(stdout);//文件out关闭
快读快写:
#include<bits/stdc++.h>
using namespace std;
inline int intfr()
{
int x = 0;
bool sign = 0;
char ch = getchar();
while(!(ch >= 48 && ch <= 57) && ch != EOF)
{
if(ch == '-')
{
sign = 1;
}
ch = getchar();
}
while(ch >= 48 && ch <= 57)
{
x = (x << 1) + (x << 3) + (ch - 48);
ch = getchar();
}
if(sign == 1)
{
return -x;
}
else
{
return x;
}
}
inline void intfp(int x)
{
char st[105];
int top = 0;
if(x < 0)
{
putchar('-');
}
do
{
top++;
if(x >= 0)
{
st[top] = (x % 10 + 48);
}
else
{
st[top] = (-(x % 10) + 48);
}
x /= 10;
}
while(x != 0);
while(top != 0)
{
putchar(st[top]);
top--;
}
}
inline long long llfr()
{
long long x = 0;
bool sign = 0;
char ch = getchar();
while(!(ch >= 48 && ch <= 57) && ch != EOF)
{
if(ch == '-')
{
sign = 1;
}
ch = getchar();
}
while(ch >= 48 && ch <= 57)
{
x = (x << 1) + (x << 3) + (ch - 48);
ch = getchar();
}
if(sign == 1)
{
return -x;
}
else
{
return x;
}
}
inline void llfp(long long x)
{
char st[105];
int top = 0;
if(x < 0)
{
putchar('-');
}
do
{
top++;
if(x >= 0)
{
st[top] = (x % 10 + 48);
}
else
{
st[top] = (-(x % 10) + 48);
}
x /= 10;
}
while(x != 0);
while(top != 0)
{
putchar(st[top]);
top--;
}
}
inline void llwriteln(long long x){
llfp(x);
putchar('/n');
}
inline void solve(){
int n=5000000;
int v;
for(int i=1;i<=n;i++)v=llfr();
for(int i=1;i<=n;i++)llwriteln(i);
}
int main(){
freopen("in.in","r",stdin);
freopen("in.out","w",stdout);
solve();
return 0;
}
但cout<<i<<'\n'最快。比llfp快。
endl耗时太大,大约13s左右。(.时间复杂度随数值个数增长)
七.常数优化
ios::sync_with_stdio(0),cin/cout.tie(0)等称为卡常数。
#include<bits/stdc++.h>
using namespace std;
mt19937 Rand(time(0));
int z[5000000],y[5000000];
int main(){
int n=5000000;
for(int i=0;i<n;i++){
y[i]=i;
}
random_shuffle(y,y+n);
for(int i=0;i<n;i++){
z[y[i]]=Rand(); //0.4412s
// z[i]=Rand();//0.4212s
}
return 0;
}
八.运算符





九.二进制移位
x/2=x>>1
x^2=x<<1

Day 2
The first lesson
一。倍增(st)
求从a[i]开始的2^i个数的最大值

#include<bits/stdc++.h>
using namespace std;
int n,a[114514],f[100010][20];
int main(){
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=n;i++)f[i][0]=a[i];
for(int j=1;(1<<j)<=n;j++)
for(int i=1;i+(i<<(j-1))<=n;i++)
f[i][j]=max(f[i][j-1],f[i+(i<<(j-1))][j-1]);
return 0;
}
求区间中的最大值
#include<bits/stdc++.h>
using namespace std;
int n,a[114514],f[100010][20],x[114514];
int main(){
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
x[1]=0;
for(int i=2;i<=n;i++)x[i]=x[i>>1]+1;
for(int j=1;(1<<j)<=n;j++)
for(int i=1;i+(i<<(j-1))<=n;i++)
f[i][j]=max(f[i][j-1],f[i+(i<<(j-1))][j-1]);
x[1]=0;
for(int i=2;i<=n;i++)x[i]=x[i>>1]+1;
cin>>m;
for(int i=1;i<=m;i++){
int l,r;
cin>>l>>r;
int len=r-l+1;
int j=x[len];
cout<<max(f[l][j],f[r-(1<<j)+1,[j])<<'\n';
}
return 0;
}

二.(1)二分法
#include<bits/stdc++.h>
using namespace std;
int n,m;
int a[114514];
signed main(){
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
sort(a+1,a+n+1);
cin>>m;
for(int i=1;i<=m;i++){
int x;
cin>>x;
int l=0,r=n;
while(l+1!=r){
int z=(l+r)>>1;
if(x<=a[z])r=z;
else l=z;
}
if(a[r]==x)cout<<"Yes";
else cout<<"No";
}
return 0;
}
(2)二分答案
检查函数:
inline void check(int t){
int sum=0;
for(int i=1;i<=n;++)
if(a[i]>t)sum+=(a[i]-t-1)/k+1;
if(sum<=t)return 1;
else return 0;
}
代码:
#include<bits/stdc++.h>
using namespace std;
int k;
inline void check(int t){
int sum=0;
for(int i=1;i<=n;i++)
if(a[i]>t)sum+=(a[i]-t-1)/k+1;
if(sum<=t)return 1;
else return 0;
}
int main(){
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
sort(a+1,a+n+1);
int l=0,r=a[n];
while(l+1!=r){
cin>>k;
}
return 0;
}
三.快速幂
int ksm(int x,int y,int p){
if(y==0)return 1;
int z=ksm(x,y/2,p);
z=1ll*z*z%p;
if(y&1)z=1ll*z*x%p;
return z;
}
四.(一)矩阵

(二)构造函数

(三)矩阵乘法
struct matrix{
int n,m;
int a[5][5];
matrix(){
n=m=0;
memset(a,0,sizeof(a));
}
};
matrix operator*(const matrix &ml,const matrix &m2){
matrix m3;
m3.n=m1.n;m3.m=m1.m;
for(int i=1;i<=m3.n;i++){
for(int j=1;j<=m3.m;j++){
for(int k=1;k<=m1.m;k++){
m3.a[i][j]+=m1.a[i][k]*m2.a[k][j];
}
}
}
return m3;
}
(四)由于作者是一个蒟蒻,所以矩阵快速幂没记完。(晚上补充)

The second lesson
一.贪心
P1080
#include<bits/stdc++.h>
using namespace std;
int n;
struct Person{
int l,r;
}p[1005];
// p[0]设为国王,p[1]~p[n]为大臣
bool cmp(Person a,Person b){
return max(b.r,a.l*a.r)<max(a.r,b.l*b.r);
//a排在b前得到最多奖赏比较少
}
int s[4005],d[4005],ans[4005];
int LEN=4004;
void cheng(int x){//高精度*单精度
for(int i=1;i<=LEN;i++) s[i]=s[i]*x;
//进位
for(int i=1;i<=LEN;i++){
s[i+1]+=s[i]/10;
s[i]%=10;
}
}
void chu(int x){//高精度/单精度
//从s最高位开始除
memset(d,0,sizeof(d));
int r=0;//余数
for(int i=LEN;i>=1;i--){
r=r*10+s[i];//当前的被除数
d[i]=r/x;
r=r%x;
}
}
bool f(){
//比较的是ans和d数组
for(int i=LEN;i>=1;i--){
if(ans[i]>d[i]) return false;
if(ans[i]<d[i]) return true;
}
return false;
}
void cpy(){
//把d赋值给ans
for(int i=1;i<=LEN;i++) ans[i]=d[i];
}
void print(){
//输出ans数组
while(ans[LEN]==0&&LEN>1) LEN--;//去前导0
for(int i=LEN;i>=1;i--) cout<<ans[i];
}
int main(){
cin>>n;
for(int i=0;i<=n;i++) cin>>p[i].l>>p[i].r;
sort(p+1,p+n+1,cmp);
s[1]=1;
for(int i=1;i<=n;i++){
cheng(p[i-1].l); //前i-1个大臣左手的乘积
//高精度乘 s[]
chu(p[i].r);//第i个大臣的奖赏
//高精度除 d[]
if(f()) cpy();
//高精度比较
//高精度赋值
}
print();
return 0;
}

二.dfs(深度优先搜索)
void dfs(int now,int nownum,int nowsum){
//当前要看第now个元素选不选
//已经选了nowsum个数
//已经选了的数的和是nowsum
if(now>n){
dfs(now+1,nownum,nowsum);
dfs(now+1,nownum+1,nowsum+a[now]);
}
}
dfs示意
劣势:时间长,一条路走到黑
三.bfs(广度优先搜索)


int step[maxn][maxn],a[maxn][maxn],n,m,sx,sy,tx,ty;
int dx[4]={-1,1,0,0};
int dy[4]={0,0,-1,1};
queue<pair<int,int> >q;
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>a[i][j];
}
}
cin>>sx>>sy;
cin>>tx>>ty;
memset(step,-1,sizeof(step));
step[sx][sy]=0;
q.push(make_pair(sx,sy));
while(q.size()){
int x=q.front().first;
int y=q.front().second;
q.pop();
for(int i=0;i<4;i++)
}
return 0;
}
四.搜索剪枝
#include<bits/stdc++.h>
using namespace std;
int ans=0,n,m,a[114514],sum[114514];
void dfs(int now,int nownum,int nowsum){
//当前要看第now个元素选不选
//已经选了nowsum个数
//已经选了的数的和是nowsum
if(nownum>m)return;//可行性剪枝
if(nownum+n-now+1<m)return;
if(nowsum+sum[n]-sum[now-1]<=ans)return;//最优性剪枝
if(now>n){
if(nownum==m)ans=max(ans,nowsum);
return;
}
dfs(now+1,nownum,nowsum);
dfs(now+1,nownum+1,nowsum+a[now]);
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i];
for(int i=1;i<=n;i++)
sum[i]+=sum[i-1]+a[i];
dfs(1,0,0);
cout<<ans<<'\n''
return 0;
}

五.搜索卡时
在0.95s时break
#include<bits/stdc++.h>
using namespace std;
int ans=0,n,m,a[114514],sum[114514];
void dfs(int now,int nownum,int nowsum){
//当前要看第now个元素选不选
//已经选了nowsum个数
//已经选了的数的和是nowsu
//clock()//程序运行了多少秒
if(1000*clock()/CLOCKS_PER_SEC>900)exit(0);//卡时
if(nownum>m)return;//可行性剪枝
if(nownum+n-now+1<m)return;
if(nowsum+sum[n]-sum[now-1]<=ans)return;//最优性剪枝
if(now>n){
if(nownum==m)ans=max(ans,nowsum);
return;
}
dfs(now+1,nownum,nowsum);
dfs(now+1,nownum+1,nowsum+a[now]);
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i];
for(int i=1;i<=n;i++)
sum[i]+=sum[i-1]+a[i];
dfs(1,0,0);
cout<<ans<<'\n''
return 0;
}
六。搜索玄学(zhx说的,不关我事)
倒着搜。
Day 3
The first lesson
一.dfs重现
#include<bits/stdc++.h>
using namespace std;
int pos[20],ans=0;
int n;
bool col[20];
bool xie1[50];
bool xie2[50];
inline void dfs(int now){
if(now>n)ans++; return;
int up=n;
if(now==1)up=up>>1;
for(int j=1;j<=n;j++){
int idx1=j-now+n;
int idx2=now+j-1;
if(!col[j]&&!xie1[idx1]=xie2[idx2]){
pos[now]=j;
col[j]=xie1[idx1]=xie2[idx2]=true;
dfs(now+1);
col[j]=xie1[idx1]=xie2[idx2]=false;
}
}
}
signed main(){
cin>>n;
dfs(1);
cout<<(ans<<1)<<'\n';
}


优化
#include<bits/stdc++.h>
using namespace std;
int pos[20],ans=0;
int n;
inline void dfs(int now){
if(now>n)ans++; return;
int up=n;
if(now==1)up=up>>1;
int s=s1|s2|s3;
for(int j=0;j<n;j++){
if(((s>>j)&1)==0){
pos[now]=j;
dfs(now+1,s1|(1<<j),s2|(1<<j),s3|(1<<j));
}
}
}
signed main(){
cin>>n;
dfs(0,0,0,0);
cout<<(ans<<1)<<'\n';
}
2.BFS重现
#include<bits/stdc++.h>
using namespace std;
queue<int>q;
int a[4][4],b[4][4],step[3265920],dx[4]={-1,1,0,0},dy[4]={0,0,-1,1};
int main(){
int s=0;
for(int i=1;i<=3;i++){
for(int j=1;j<=3;j++){
cin>>a[i][j];
s=s*10+a[i][j];
}
}
memset(step,-1,sizeof(step));
step[s]=0;
q.push(s);
while(q.size()){
int ss=q.front();
int cur_step=step[s];
q.pop();
int x,y;
memset(vis,0,sizeof(vis));
for(int i=3;i>=1;i--){
for(int j=3;j>=1;j--){
a[i][j]=s%10;
s=s/10;
if(a[i][j]==0)x=i,y=j;
}
}
for(int d=0;d<4;d++){
int xx=x+dx[i];
int yy=y+dy[d];
if(xx>=1&&xx<=3&&yy>=1&&yy<=3){
swap(a[x][y],a[xx][yy]);
s=0;
for(int i=1;i<=3;i++){
for(int j=1;j<=3;j++){
s=s*10+a[i][j];
}
}
}
}
}
return 0;
}
阶乘优化(换成9进制)

三.如何优化BFS
1.双向BFS
The second lesson
一.图论






vector<pair<int,int> >z[maxn];
inline add_edge(int s,int e,int d){
z[s].push_back(make_pair(e,d));
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
int s,e,d;
cin>>s>>e>>d;
add_edge(s,e,d);
add_edge(e,s,d);
}
for(int i=1;i<=n;i++){
for(int j=0;j<z[i].size();j++){
int e=z[i][j].first;
int d=z[i[j].second;
}
}
}

填色
vector<pair<int,int> >z[maxn];
inline add_edge(int s,int e,int d){
z[s].push_back(make_pair(e,d));
}
int col[maxn];
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
int s,e,d;
cin>>s>>e>>d;
add_edge(s,e,d);
add_edge(e,s,d);
}
for(int i=1;i<=n;i++){
if(col[i]!=0)continue;
col[1]=1;
queue<int>q;
q.push(1);
while(q.size()){
int i=q.front();
q.pop();
for(int j=0;j<z[i].size();j++){
int k=z[i][j];
if(!col[k]){
col[k]=3-col[i];
q.push(k);
}
else{
if(col[k]==col[i]){
cout<<"bushierfentu";
exit(0);
}
}
}
cout<<"shierfentu";
}
树


倍增求lca
#include<bits/stdc++.h>
using namespace std;
vector<int>z[maxn];
int n,m;
inline void add_edge(int s,int e){
z[s].push_back(e);
}
int depth[maxn],f[maxn][20];
inline void dfs(int i,int j){
f[i][0]=j;
for(int k=1;k<=19;k++)f[1][k]=f[f[i][k-1]][k-1];
depth[i]=depth[j]+1;
for(int k=0;k<z[i].size();k++){
int l=z[i][k];
if(l!=j)dfs(l,i);
}
}
inline int get_lca(int p1,int p2){
if(depth[p1]<depth[p2])swap(p1,p2);
for(int i=19;i>=0;i--)if(depth[f[p1][i]]>=depth[p2])p1=f[p1][i];
if(p1==p2)return p1;
for(int i=19;i>=0;i--)if(f[p1)[i]!=f[p2][i]}p1=f[p1][i],p2=f[p2][i];
return f[p1][0];
}
signed main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
int s,e;
cin>>s>>e;
add_edge(s,e);
add_edge(e,s);
}
dfs(1,0);
cout<<get_lca();
return 0;
}
Day 4
The First lesson
一.最短路

(1)floyd算法//O(n^3)
本质是dp.

#define maxn 100
int dist[maxn][maxn][maxn];
int main(){
memset(dist,0x3f,sizeof(dist));
cin>>n>>m;
for(int i=1;i<=n;i++{
int s,e,d;
cin>>s>>e>>d;
dist[0][s][e]=min(dist[0][s][e],d);
}
for(int i=1;i<=n;i++){
dist[0][i][i]=0;
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
for(int k=1;k<=n;k++){
dist[i][j][k]=min(dist[i-1][j][k],dist[i-1][j][i]+dist[i-1][i][k])
}
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
cout<<dist[n][i][j]<<'\n';
}
}
return 0;
}

优化:(压维)
#include<bits/stdc++.h>
using namespace std;
#define maxn 100
int dist[maxn][maxn];
int main(){
memset(dist,0x3f,sizeof(dist));
cin>>n>>m;
for(int i=1;i<=n;i++{
int s,e,d;
cin>>s>>e>>d;
dist[s][e]=min(dist[s][e],d);
}
for(int i=1;i<=n;i++){
dist[i][i]=0;
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
for(int k=1;k<=n;k++){
dist[j][k]=min(dist[j][k],dist[j][i]+dist[i][k])
}
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
cout<<dist[i][j]<<'\n';
}
}
return 0;
}
(2)单源最短路

dijkstra:

vector<pair<int,int> >z[maxn];
inline void add_edge(int a,int b,int c){
z[a].push_back(make_pair(b,c));
}
inline void dijkstra(int s){
memset(dist,0x3f,sizeof(dist));
dist[s]=0;
for(int i=1;i<=n;i++){
int p=0;
for(int j=1;j<=n;j++){
if(!vis[j]&&(p==0||dist[j]<dist[p]))p=j;
}
vis[p]=true;
for(int j=1;j<=z[p].size();j++){
int q.z[p][j].first;
int d=z[p][j].second;
if(dist[q]>dist[p]+d)dist[q]=dist[p]+d;
}
}
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
int s,e,d;
cin>>s>>e>>d;
add_edge(s,e,d);
}
dijkstra();
for(int i=1;i<=n;i++){
cout<<dist[i]<<'\n';
}
return 0;
}
spfa:

vector<pair<int,int> >z[maxn];
inline void add_edge(int a,int b,q.frint c){
z[a].push_back(make_pair(b,c));
}
inline void spfa(int s){
memset(dist,0x3f,sizeof(dist));
dist[s]=0;
queue<int>q;
q.push(s);
vis[s]=true;
while(q.size()){
int p=q.front();
q.pop();
vis[p]=false;
for(int i=0;i<z[p].size();i++){
int e=z[p][i].first;
int d=z[p][i].second;
if(dist[e]>dist[p]+d){
dist[e]=dist[p]+d;
if(!vis[e])q.push(e),vis[e]=true;
}
}
}
for(int i=1;i<=n;i++){
int p=0;
for(int j=1;j<=n;j++){
if(!vis[j]&&(p==0||dist[j]<dist[p]))p=j;
}
vis[p]=true;
for(int j=1;j<=z[p].size();j++){
int q.z[p][j].first;
int d=z[p][j].second;
if(dist[q]>dist[p]+d)dist[q]=dist[p]+d;
}
}
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
int s,e,d;
cin>>s>>e>>d;
add_edge(s,e,d);
}
spfa();
for(int i=1;i<=n;i++){
cout<<dist[i]<<'\n';
}
return 0;
}


The second lesson
一.生成树

kruscal算法:

#include<bits/stdc++.h>
using namespace std;
#define maxn 1414114
int to[maxn];
inline int go(int p){
if(to[p]==p)return p;
else return to[p]=go(to[p]);
}
inline bool cmp(edge a,edge b){
return a.d<b.d;
}
struct edge{
int s,e,d;
}ed[maxn];
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++)cin>>ed[i].s>>ed[i].e>>ed[i].d;
sort(ed+1,ed+m+1,cmp);
for(int i=1;i<=n;i++)to[i]=i;
int ans=0;
for(int i=1;i<=m;i++){
int p1=ed[i].s,p2=ed[i].e,d=ed[i].d;
if(go(p1)!=go(p2)){
ans+=d;
to[go(p1)]=go(p2);
}
}
cout<<ans<<'\n';
return 0;
}




Day 5
The First Lesson
一.二分图匹配
(一)匈牙利算法

二.强连通问题

The second Lesson
动态规划(DP)
需运用递推式。
int f[maxn];
bool g[maxn];
int dfs(int n){//记忆化搜索(a*)
if(n==0)return 0;
if(n==1)return 1;
if(g[n])return f[n];
g[n]=true;
f[n]=dfs(n-1)+dfs(n-2);
return dfs(n-1)+dfs(n-2);
}
int main(){
cin>>n;
f[0]=0;
f[1]=1;
/*for(int i=2;i<=n;i++){
f[i]=f[i-1]+f[i-2];
}*/
/*for(int i=0;i<=n;i++){
f[i+1]+=f[i];
f[i+2]+=f[i];
}*/
//cout<<f[n]<<'\n';
cout<<dfs(n)<<'\n';
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
cin>>a[i][j];
f[1][1]=a[1][1];
for(int i-1;i<=n;i++)
for(int j=1;j<=m;j++)
f[i][j]=max(f[i-1][j],f[i][j-1])+a[i][j];
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
f[i+1][j]=max(f[i+1][j],f[i][j]+a[i+1][j]);
}
}
最长上升子序列(LIS)

#include<bits/stdc++.h>
using namespace std;
#define maxn 114514
int f[maxn];
signed main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
}
for(int i=1;i<=n;i++){
for(int j=1;j<i;j++)
if(a[j]<a[i])f[i]=max(f[i],f[j]);
f[i]++;
}
int ans=0;
for(int i=1;i<=n;i++)
ans=max(ans,f[i]);
cout<<ans<<'\n';
return 0;
}
分类:


#include<bits/stdc++.h>
using namespace std;
int f[1005][1005];
int n;
signed main(){
cin>>n;
f[1][0]=1;
for(int i=1;i<=n;i++){
for(int j=0;j<=i*(i-1)/2;i++){
for(int k=0;k<=i;k++){
f[i+1][j+i-k]+=f[i][j];
}
}
}
int ans=0;
for(int j=0;j<=n*(n-1)/2;j+=2)ans+=f[n][j];
cout<<ans<<'\n';
}
'
Day 6
动态规划(DP)
背包DP

#include<bits/stdc++.h>
using namespace std;
int f[1145][1145],v[1145],w[1145];
int main(){
cin>>n>>m;
for(int i=1;i<=m;i++){
cin>v[i]>>w[i];
}
for(int i=0;i<n;i++){
for(int j=0;j<=m;j++){
f[i+1][j]=max(f[i][j],f[i+1][j]);
f[i+1][j+v[i+1]]=max(f[i+1][j+v[i+1]],f[i][j]+w[i+1]);
}
}
int ans=0;
for(int i=0;i<=m;i++){
ans=max(ans,f[n][i]);
}
cout<<ans<<'\n';
return 0;
}
区间DP
int f[maxn][maxn];
int main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
}
for(int i=1;i<=n;i++){
sum[i]=sum[i-1]+a[i];
}
memset(f,0x3f,sizeof(f));
for(int i=1;i<=n;i++){
f[i][i]=0;
}
for(int l=1;l<=n;l++)
for(int r=l;r<=n;r++)
for(int k=l;k<r;k++)
f[l][r]=min(f[l][r],f[l][k]+f[k+1][r]+sum[r]-sum[l-1]);
cout<<f[1][n]<<'\n';
}

树形DP
int f[maxn];
vector<int>z[maxn];
inline void add_edge(int s,int e){
z[s][e].push_back(s,e);
}
void dfs(int p,int f){
for(int i=0;i<z[p].size();i++){
int q=z[p][i];
if(q!=f)dfs(q,p);
}
f[p]=1;
for(int i=0;i<z[p].size;i++){
int q=z[p][i];
if(q!=f)f[p]+=f[q];
}
}
int main()[
cin>>n;
for(int i=1;i<n;i++){
int s,e;
cin>>s>>e;
add_edge(s,e);
add_edge(e,s);
}
dfs(1,0);
}
数位DP

int f[30][2];
int get(int x){
int n=0;
while(x_!=0){
n++;
x[n]=x_%10;
x_/=10;
}
memset(f,0,sizeof(f));
f[n+1][1]=1;
for(int i=n;i>=1;i--)
for(int j=0;j<2;j++){
int up=9;
if(j==1)up=x[i];
for(int k=0;k<=up;k++)
f[i][(j==1)&&(k==up)]+=f[i+1][j];
}
return f[1][0]+f[1][1];
}
int main(){
cin>l>>r;
cout<<get(r)-get(l-1)<<endl;
}

浙公网安备 33010602011771号