算法模板(二)
并查集:
int f[100005];
int num[100005];
int n,m;
int find(int x)
{
int r=x;
while(f[r]!=r)
r=f[r];
int i=x,j;
while(i!=r)
{
j=f[i];
f[i]=r;
i=j;
}
return r;
}
void tr(int x,int y)
{
if(find(x)!=find(y))
{
f[find(y)]=find(x);
}
}
多重背包:
#include <bits/stdc++.h>
using namespace std;
int f[20005];
int n,m;
int v[20005],w[20005];
int main ()
{
cin>>n>>m;
int cnt=0;
for(int i=1;i<=n;i++)
{
int a,b,c;
cin>>a>>b>>c;
int k=1;
while(c>k)
{
cnt++;
v[cnt]=k*a;
w[cnt]=k*b;
c-=k;
k*=2;
}
if(c>0)
{
cnt++;
v[cnt]=c*a;
w[cnt]=c*b;
}
}
for(int i=1;i<=cnt;i++)
for(int j=m;j>=v[i];j--)
f[j]=max(f[j],f[j-v[i]]+w[i]);
cout<<f[m]<<endl;
return 0;
}
最长上升子序列:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll num[1005],f[1005];
int n;
int main ()
{
cin>>n;
for(int i=1;i<=n;i++) cin>>num[i];
for(int i=1;i<=n;i++)
{
f[i]=1;
for(int j=1;j<=i;j++)
if(num[j]<num[i])
f[i]=max(f[i],f[j]+1);
}
ll y=0;
for(int i=1;i<=n;i++)
y=max(f[i],y);
cout<<y<<endl;
return 0;
}
快速排序:
int n,num[100050];
void sq(int l,int r)
{
if(l>=r) return ;
int x=num[(l+r)/2],i=l-1,j=r+1;
while(i<j)
{
do i++;while(num[i]<x);
do j--;while(num[j]>x);
if(i<j) swap(num[i],num[j]);
}
sq(l,j);
sq(j+1,r);
}
归并排序:
int n,num[100050],mm[100050];
void ms(int l,int r)
{
if(l>=r) return ;
int mid=l+r>>1;
ms(l,mid);ms(mid+1,r);
int k=0,i=l,j=mid+1;
while(i<=mid&&j<=r)
{
if(num[i]<=num[j]) mm[k++]=num[i++];
else mm[k++]=num[j++];
}
while(i<=mid) mm[k++]=num[i++];
while(j<=r) mm[k++]=num[j++];
for(i=l,j=0;i<=r;i++,j++) num[i]=mm[j];
}
Dijkstra:
const int N = 500 + 9;const int inf = 0x3f;
bool ch[N];int mp[N][N];int di[N];int n, m;
int cmp()
{
memset(di, inf, sizeof(di));
di[1] = 0;
for(int i = 0; i < n; i++)
{
int t = -1;
for(int j = 1; j <= n; j++)
{
if(!ch[j] && (t == -1 || di[j] < di[t]))
t = j;
}
ch[t] = true;
for(int j = 1; j <= n; j++)
{
di[j] = min(di[j], di[t] + mp[t][j]);
}
}
if(di[n] == 0x3f3f3f3f) return -1;
else return di[n];
}
Bellman_ford
int bellman_ford()
{
memset(dist, 0x3f, sizeof(dist));
dist[1] = 0;
for(int i = 1; i <= k; i++)
{
memcpy(backup, dist, sizeof(dist));
for(int j = 1; j <= m; j++)
{
int a = edget[j].a, b = edget[j].b, w = edget[j].w;
dist[b] = min(dist[b], backup[a] + w);
}
}
if(dist[n] > 0x3f3f3f3f / 2) return -1;
else return dist[n];
}
Spfa:
bool st[N];
int dist[N];
int n, m;
int h[N], w[N], e[N], ne[N], idx;
void add(int a, int b, int c)
{
e[idx] = b; w[idx] = c; ne[idx] = h[a]; h[a] = idx++;
}
int spfa()
{
memset(dist, 0x3f, sizeof(dist));
dist[1] = 0;
queue<int> q;
q.push(1);
st[1] = true;
while(q.size())
{
int t;
t = q.front();
q.pop();
st[t] = false;
for(int i = h[t]; i != -1; i = ne[i])
{
int j = e[i];
if(dist[j] > dist[t] + w[i])
{
dist[j] = dist[t] + w[i];
if(!st[j])
{
q.push(j);
st[j] = true;
}
}
}
}
return dist[n];
}
Floyd:
#include<bits/stdc++.h>
using namespace std;
const int N = 0x3f3f3f3f;
int d[209][209];
void floyd()
{
for(int o = 1; o <= n; o ++)
for(int i = 1; i <= n; i ++)
for(int j = 1; j <= n; j ++)
d[i][j] = min(d[i][j], d[i][o] + d[o][j]);
}
void ch()
{
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
if(i == j) d[i][j] = 0;
else d[i][j] = N;
}
Prim:
int prim()
{
memset(dist, inf, sizeof dist);
int res = 0;
for(int i = 0; i < n; i ++)
{
int t = -1;
for(int j = 1; j <= n; j++)
{
if(!ch[j] && (t == -1 || dist[t] > dist[j]))
t = j;
}
if(i && dist[t] == inf) return inf;
if(i) res += dist[t];
ch[t] = true;
for(int j = 1; j <= n; j++) dist[j] = min(dist[j], mp[t][j]);
}
return res;
}
Kruskal
int p[N];
typedef struct
{
int a, b, w;
}pop;
pop mp[N];
bool cmp(pop x, pop y)
{
return x.w < y.w;
}
int find(int x)
{
if(p[x] != x) p[x] = find(p[x]);
return p[x];
}
int kruskal()
{
for(int i = 1; i <= n; i++) p[i] = i;
sort(mp + 1, mp + 1 + m, cmp);
int res = 0, cnt = 0;
for(int i = 1; i <= m; i++)
{
int a = mp[i].a, b = mp[i].b, w = mp[i].w;
a = find(a);
b = find(b);
if(a != b)
{
p[a] = b;
cnt ++;
res += w;
}
}
if(cnt < n - 1) return inf;
else return res;
}
染色法判定二分图:
int h[N / 2], e[N], ne[N], idx;
int co[N / 2];
void add(int a, int b)
{
e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
bool dfs(int u, int c)
{
co[u] = c;
for(int i = h[u]; i != -1; i = ne[i])
{
int j = e[i];
if(!co[j])
{
if(!dfs(j, 3 - c)) return false;
}
else if (co[j] == c) return false;
}
return true;
}
匈牙利算法:
bool find(int x)
{
for(int i = h[x]; i != -1; i = ne[i])
{
int j = e[i];
if(!st[j])
{
st[j] = true;
if(ch[j] == 0 || find(ch[j]))
{
ch[j] = x;
return true;
}
}
}
return false;
}
扩展欧几里得:
int exgcd(int a, int b, int &x, int &y)
{
if(!b)
{
x = 1;
y = 0;
return a;
}
int d = exgcd(b, a % b, y, x);
y -= a / b * x;
return d;
}
线段树(无pushdown,单点修改,区间查询):
const int N = 2e5 + 9;
struct tree
{
int l, r;
int v;
}tr[N * 4];
void pushup(int u)
{
tr[u].v = max(tr[u << 1].v, tr[u << 1 | 1].v);
}
void build(int u, int l, int r)
{
tr[u].l = l;
tr[u].r = r;
int mid = l + r >> 1;
if(l == r) return ;
build(u << 1, l, mid);
build(u << 1 | 1, mid + 1, r);
}
int query(int u, int l, int r)
{
if(tr[u]. l >= l && tr[u].r <= r) return tr[u].v;
int v = 0;
int mid = tr[u].l + tr[u].r >> 1;
if(mid >= l) v = query(u << 1, l, r);
if(mid < r) v = max(v, query(u << 1 | 1, l, r));
return v;
}
void modify(int u, int x, int v)
{
if(tr[u].l == x && tr[u].r == x) tr[u].v = v;
else
{
int mid = tr[u].l + tr[u].r >> 1;
if(mid >= x) modify(u << 1, x, v);
else modify(u << 1 | 1, x, v);
pushup(u);
}
}
线段树(有pushdown,区间修改,区间查询)
#include <iostream>
using namespace std;
typedef long long ll;
const ll N = 1e5 + 9;
int w[N];
int n, m;
typedef struct
{
int l, r;
ll sum, add;
}pop;
pop tr[4 *N];
void pushup(int u)
{
tr[u].sum = tr[u << 1].sum + tr[u << 1 | 1].sum;
}
void pushdown(int u)
{
pop &root = tr[u], &left = tr[u << 1], &right = tr[u << 1 | 1];
if(root.add)
{
left.add += root.add;
left.sum += (ll)(left.r - left.l + 1) * root.add;
right.add += root.add;
right.sum += (ll)(right.r - right.l + 1) * root.add;
root.add = 0;
}
}
void build(int u, int l, int r)
{
if(l == r)
{
tr[u].l = l;
tr[u].r = r;
tr[u].sum = w[r];
tr[u].add = 0;
}
else
{
tr[u].l = l;
tr[u].r = r;
int mid = (l + r) >> 1;
build(u * 2, l, mid);
build(u * 2 + 1, mid + 1, r);
pushup(u);
}
}
void modify(int u, int l, int r, int d)
{
pop &oi = tr[u];
if(oi.l >= l && oi.r <= r)
{
oi.sum += (ll)(oi.r - oi.l + 1) * d;
oi.add += d;
}
else
{
pushdown(u);
int mid = (oi.l + oi.r) >> 1;
if(l <= mid) modify(u * 2, l, r, d);
if(r > mid) modify(u * 2 + 1, l , r, d);
pushup(u);
}
}
ll query(int u, int l, int r)
{
pop &oi = tr[u];
if(oi.l >= l && oi.r <= r) return oi.sum;
pushdown(u);
int mid = (oi.l + oi.r) >> 1;
ll sum = 0;
if(l <= mid) sum = query(u * 2, l, r);
if(r > mid) sum += query(u * 2 + 1, l, r);
return sum;
}
线段树具体函数使用:
build(1, 1, n);//初始建树
modify(1, m + 1, x);//朴素版修改方式
modify(1, l, r, d);//进阶版修改方式
query(1, l, r);//查询