树与图的遍历
时间复杂度 O(n+m), n表示点数,m表示边数
(1) 深度优先遍历 —— 模板题 AcWing 846. 树的重心
int dfs(int u){
vis[u]=1;
int son_size=1,now=0;
ee(i,u){
int v=e[i].v;
if(!vis[v]){
int t=dfs(v);
now=max(now,t);
son_size+=t;
}
}
now=max(now,n-son_size);
ans=min(ans,now);
return son_size;
}
(2) 宽度优先遍历 —— 模板题 AcWing 847. 图中点的层次
queue<int>q;
inline void spfa(){
mem(dis,0x3f);
mem(vis,0);
q.push(1);
vis[1]=1;
dis[1]=0;
while(!q.empty()){
int u=q.front();q.pop();
vis[u]=0;
ee(i,u){
int v=e[i].v,w=e[i].w;
if(dis[v]>dis[u]+w){
dis[v]=dis[u]+w;
if(!vis[v]){
vis[v]=1;
q.push(v);
}
}
}
}
}
拓扑排序 —— 模板题 AcWing 848. 有向图的拓扑序列
时间复杂度 O(n+m), n表示点数,m表示边数
queue<int>q;
bool topo(){
rep(i,1,n)
if(!deg[i])
q.push(i);
while(!q.empty()){
int u=q.front();q.pop();
topon[++tot]=u;
ee(i,u){
int v=e[i].v;
if(--deg[v]==0)
q.push(v);
}
}
return tot==n;
}
堆优化版dijkstra —— 模板题 AcWing 850. Dijkstra求最短路 II
时间复杂度 O(mlogn), n表示点数,m表示边数
priority_queue<pair<int,int> >q;
inline void dij(){
mem(dis,0x3f);
mem(vis,0);
q.push(make_pair(0,1));
dis[1]=0;
while(!q.empty()){
int u=q.top().second;q.pop();
if(vis[u])continue;
vis[u]=1;
ee(i,u){
int v=e[i].v,w=e[i].w;
if(dis[v]>dis[u]+w){
dis[v]=dis[u]+w;
q.push(make_pair(-dis[v],v));
}
}
}
}
Bellman-Ford算法 —— 模板题 AcWing 853. 有边数限制的最短路
时间复杂度 O(nm), n表示点数,m表示边数
#define N 510
#define M 10010
int n,m,k;
int dis[N],backup[N];
//使用backup数组的目的是为了防止松弛的次数大于k
struct Edge{
int u, v, w;
}e[M];
inline int bellman_ford(){
mem(dis,0x3f);
dis[1]=0;
rep(i,1,k){
memcpy(backup,dis,sizeof(dis));
rep(j,1,m){
int u=e[j].u,v=e[j].v,w=e[j].w;
if(backup[u]!=0x3f3f3f3f && dis[v]>backup[u]+w){
dis[v]=backup[u]+w;
}
}
}
if(dis[n]==0x3f3f3f3f)return -1;
else return dis[n];
}
int main(){
rd(n),rd(m),rd(k);
rep(i,1,m){
rd(e[i].u),rd(e[i].v),rd(e[i].w);
}
int t=bellman_ford();
if (t==-1) puts("impossible");
else printf("%d\n", t);
return 0;
}
spfa 算法(队列优化的Bellman-Ford算法) —— 模板题 AcWing 851. spfa求最短路
时间复杂度 平均情况下 O(m),最坏情况下 O(nm), n表示点数,m表示边数
queue<int>q;
inline void spfa(){
mem(dis,0x3f);
mem(vis,0);
q.push(1);
vis[1]=1;
dis[1]=0;
while(!q.empty()){
int u=q.front();
q.pop();
vis[u]=0;
ee(i,u){
int v=e[i].v,w=e[i].w;
if(dis[v]>dis[u]+w){
dis[v]=dis[u]+w;
if(!vis[v]){
vis[v]=1;
q.push(v);
}
}
}
}
}
spfa判断图中是否存在负环 —— 模板题 AcWing 852. spfa判断负环
时间复杂度是 O(nm), n表示点数,m表示边数
- 不需要初始化dist数组
原理:如果某条最短路径上有n个点(除了自己),那么加上自己之后一共有n+1个点,由抽屉原理一定有两个点相同,所以存在环。 - cnt数组表示到达当前这个点最短路的边数,如果cnt[x]>=n,说明至少经过了n条边,即n+1个点,由抽屉原理可知显然有两个点重复,即存在负环
#define N 100010
int head[N],tot,dis[N],cnt[N];
bool vis[N];
struct Edge{
int v,next,w;
}e[N<<1];
void add(int u,int v,int w){e[++tot].v=v;e[tot].w=w;e[tot].next=head[u];head[u]=tot;}
int n,m,s;
queue<int>q;
inline bool spfa(int s){
mem(dis,0)//本题可以不做初始化,但加上了也没事,所以就加上呗
mem(vis,0);
mem(cnt,0);
rep(i,1,n){
vis[i]=1;
q.push(i);
}////判整个图的负环要将每个节点都加入
while(!q.empty()){
int u=q.front();
q.pop();
vis[u]=0;
ee(i,u){
int v=e[i].v,w=e[i].w;
if(dis[v]>dis[u]+w){
dis[v]=dis[u]+w;
cnt[v]=cnt[u]+1;
if(cnt[v]>=n)return 1;
if(!vis[v]){
vis[v]=1;
q.push(v);
}
}
}
}
return 0;
}
int main(){
rd(n),rd(m);
rep(i,1,m){
int x,y,z;rd(x),rd(y),rd(z);
add(x,y,z);
}
if(spfa(1))
printf("Yes\n");
else
printf("No\n");
return 0;
}
floyd算法 —— 模板题 AcWing 854. Floyd求最短路
时间复杂度是 O(n^3)
, n表示点数
/*
*如果有负权边,虽然a,b不连通,但之间的距离也会因为负权边的更新小于INF,
因为INF/2也是一个很大的数,所以就用>INF/2来代表不能连通
#define N 210
int dis[N][N];
int n,m,k;
inline void floyd(){
rep(k,1,n)
rep(i,1,n)
rep(j,1,n)
dis[i][j]=min(dis[i][k]+dis[k][j],dis[i][j]);
}
int main(){
rd(n),rd(m),rd(k);
mem(dis,0x3f);
rep(i,1,n)dis[i][i]=0;/////////////////////////////
rep(i,1,m){
int x,y,z;rd(x),rd(y),rd(z);
dis[x][y]=min(dis[x][y],z);///////////////////////
}
floyd();
while(k--){
int x,y;rd(x),rd(y);
if(dis[x][y]>0x3f3f3f3f/2)printf("impossible\n");///////////////////////
else printf("%d\n",dis[x][y]);
}
//printf("%d",0x3f3f3f3f);
return 0;
}
朴素版prim算法 —— 模板题 AcWing 858. Prim算法求最小生成树
时间复杂度是 O(n^2+m), n表示点数,m表示边数
int n; // n表示点数
int g[N][N]; // 邻接矩阵,存储所有边
int dist[N]; // 存储其他点到当前最小生成树的距离
bool st[N]; // 存储每个点是否已经在生成树中
// 如果图不连通,则返回INF(值是0x3f3f3f3f), 否则返回最小生成树的树边权重之和
int prim()
{
memset(dist, 0x3f, sizeof dist);
int res = 0;
for (int i = 0; i < n; i ++ )
{
int t = -1;
for (int j = 1; j <= n; j ++ )
if (!st[j] && (t == -1 || dist[t] > dist[j]))
t = j;
if (i && dist[t] == INF) return INF;
if (i) res += dist[t];
st[t] = true;
for (int j = 1; j <= n; j ++ ) dist[j] = min(dist[j], g[t][j]);
}
return res;
}
Kruskal算法 —— 模板题 AcWing 859. Kruskal算法求最小生成树
时间复杂度是 O(mlogm), n表示点数,m表示边数
#define N 100010
struct edge{
int u,v,w;
bool operator < (const edge &rhs)const{
return w<rhs.w;
}
}e[N<<1];
int f[N],n,m,ans,cnt;
inline int find(int x){return x==f[x]?x:f[x]=find(f[x]);}
inline void kruskal(){
sort(e+1,e+m+1);
rep(i,1,n)f[i]=i;
rep(i,1,m){
int fx=find(e[i].u),fy=find(e[i].v);
if(fx==fy)continue;
f[fx]=fy;
ans+=e[i].w;
if(++cnt==n-1)break;
}
}
#undef int
int main(){
#define int long long
#ifdef WIN32
freopen("","r",stdin);
#endif
rd(n),rd(m);
rep(i,1,m){
rd(e[i].u),rd(e[i].v),rd(e[i].w);
}
kruskal();
if(cnt<n-1)printf("impossible\n");
else printf("%lld\n",ans);
return 0;
}
染色法判别二分图 —— 模板题 AcWing 860. 染色法判定二分图
时间复杂度是 O(n+m), n表示点数,m表示边数
#define N 200010
#define M
int head[N],tot,col[N],s1,cnt,n,m;
bool vis[N];
//col 表示每个点的颜色,-1表示未染色,-2表示白色,1表示黑色
struct edge{
int v,w,next;
}e[N<<1];
inline void add(int u,int v){e[++tot].v=v;e[tot].next=head[u];head[u]=tot;}
queue<pair<int,int> >q;
inline bool bfs(){
col[1]=1;
q.push(make_pair(1,1));
while(!q.empty()){
int u=q.front().first;
int color=q.front().second;
q.pop();
ee(i,u){
int v=e[i].v;
if(col[v]==-1){
col[v]=~color;
q.push(make_pair(v,col[v]));
}
else if(col[v]==col[u])return 0;
}
}
return 1;
}
int main(){
//freopen("erfen.txt","r",stdin);
rd(n),rd(m);
rep(i,1,m){
int u,v;rd(u),rd(v);
add(u,v),add(v,u);
}
mem(col,-1);
if(bfs())printf("Yes\n");
else printf("No\n");
return 0;
}
/*
4 4
1 3
1 4
2 3
2 4
*/
//Yes
//col的值有三种,-1(初始值),-2,1;
匈牙利算法 —— 模板题 AcWing 861. 二分图的最大匹配
时间复杂度是 O(nm), n表示点数,m表示边数
#define N 510
#define M 100010
int head[N],cnt;
struct edge{
int v,next;
}e[M];
inline void add(int u,int v){e[++cnt].v=v;e[cnt].next=head[u];head[u]=cnt;}
int match[N];
bool vis[N];//考虑过
int n1,n2,m,ans;
inline bool dfs(int u){
ee(i,u){
int v=e[i].v;
if(!vis[v]){
vis[v]=1;
if(match[v]==0 || dfs(match[v])){
match[v]=u;
return 1;
}
}
}
return 0;
}
#undef int
int main(){
#define int long long
//freopen("erfen.txt","r",stdin);
rd(n1),rd(n2),rd(m);
while(m--){
int u,v;rd(u),rd(v);
add(u,v);
}
mem(match,0);
rep(i,1,n1){
mem(vis,0);
if(dfs(i))
ans++;
}
printf("%lld",ans);
return 0;
}