一、生成树
洛谷模板最小生成树【跑的还算快的
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define N 5020 #define M 200008 using namespace std; int n,m,ans; int tot; int fa[N]; struct E{ int x,y,z; }e[M]; bool cmp(E a,E b){ return a.z<b.z; } int f(int x){ return fa[x]==x?x:fa[x]=f(fa[x]); } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=m;i++)scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].z); for(int i=1;i<=n;i++)fa[i]=i; sort(e+1,e+m+1,cmp); for(int i=1;i<=m;i++){ int x=e[i].x,y=e[i].y; int fx=f(x),fy=f(y); if(fx!=fy){ fa[fx]=fy; ans+=e[i].z; if(++tot==n-1)break; } } if(tot!=n-1)cout<<"orz\n"; else printf("%d\n",ans); return 0; }
kruskal
#include<iostream> #include<cstdio> #include<cstring> #define N 5020 #define M 200009 #define inf 10000000 using namespace std; int n,m,sumedge,ans,dis[N],head[N]; bool vis[N]; struct Edge{ int x,y,z,nxt; Edge(int x=0,int y=0,int z=0,int nxt=0): x(x),y(y),z(z),nxt(nxt){} }edge[M<<1]; void add(int x,int y,int z){ edge[++sumedge]=Edge(x,y,z,head[x]); head[x]=sumedge; } void prim(){ memset(dis,0x3f,sizeof(dis)); dis[1]=0; for(int i=1;i<=n;i++){ int u=-1,mn=inf; for(int j=1;j<=n;j++){ if(dis[j]<mn&&!vis[j]){ u=j;mn=dis[j]; } } if(u==-1){ ans=-1;return; } vis[u]=true;ans+=dis[u]; for(int x=head[u];x;x=edge[x].nxt){ int v=edge[x].y; if(dis[v]>edge[x].z)dis[v]=edge[x].z; } } } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=m;i++){ int x,y,z; scanf("%d%d%d",&x,&y,&z); add(x,y,z);add(y,x,z); } prim(); if(ans==-1)cout<<"orz\n"; else cout<<ans; return 0; }
prim
二、最短路
memset(dis,0x3f,sizeof(dis)); for(int i=1;i<=n;i++)dis[i][i]=0; for(int k=1;k<=n;k++) for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
floyed
#include<iostream> #include<cstdio> #include<cstring> #define maxn 10009 #define inf 2147483647 using namespace std; int n,m,s,sumedge; int dis[maxn],vis[maxn],head[maxn]; struct Edge{ int x,y,z,nxt; Edge(int x=0,int y=0,int z=0,int nxt=0): x(x),y(y),z(z),nxt(nxt){} }edge[maxn*51]; void add(int x,int y,int z){ edge[++sumedge]=Edge(x,y,z,head[x]); head[x]=sumedge; } void di(){ for(int i=1;i<=n;i++)dis[i]=inf; dis[s]=0; for(int i=1;i<=n;i++){ int k,mn=inf; for(int j=1;j<=n;j++){ if(!vis[j]&&dis[j]<mn){ mn=dis[j];k=j; } } if(mn==inf)break; vis[k]=true; for(int j=head[k];j;j=edge[j].nxt){ int v=edge[j].y; if(!vis[v]&&dis[v]>dis[k]+edge[j].z) dis[v]=dis[k]+edge[j].z; } } } int main(){ scanf("%d%d%d",&n,&m,&s); for(int i=1;i<=m;i++){ int x,y,z; scanf("%d%d%d",&x,&y,&z); add(x,y,z); } di(); for(int i=1;i<=n;i++)printf("%d ",dis[i]); return 0; }
没有优化的dijkstra
//waiting
void spfa(){ memset(dis,0x3f,sizeof(dis)); memset(vis,0,sizeof(vis)); while(!q.empty())q.pop(); dis[1]=0;vis[1]=true;q.push(1); while(!q.empty()){ int now=q.front();q.pop();vis[now]=false; for(int i=head[now];i;i=edge[i].nxt){ int v=edge[i].y; if(dis[v]>dis[now]+edge[i].z){ dis[v]=dis[now]+edge[i].z; if(!vis[v]){ vis[v]=true;q.push(v); } } } } }
spfa
三、二分图
#include<iostream> #include<cstdio> #include<cstring> #define N 1020 using namespace std; int n,m,e,ans,sumedge; int vis[N],match[N],head[N]; struct Edge{ int x,y,nxt; Edge(int x=0,int y=0,int nxt=0): x(x),y(y),nxt(nxt){} }edge[N*N]; void add(int x,int y){ edge[++sumedge]=Edge(x,y,head[x]); head[x]=sumedge; } bool dfs(int x){ for(int i=head[x];i;i=edge[i].nxt){ int v=edge[i].y; if(!vis[v]){ vis[v]=true; if(match[v]==0||dfs(match[v])){ match[v]=x;return true; } } } return false; } int main(){ scanf("%d%d%d",&n,&m,&e); for(int i=1;i<=e;i++){ int x,y; scanf("%d%d",&x,&y); if(y>m||x>n)continue; add(x,y); } for(int i=1;i<=n;i++){ memset(vis,0,sizeof(vis)); if(dfs(i))ans++; } cout<<ans<<endl; return 0; }
洛谷模板二分图匹配
封锁阳光大学
#include<iostream> #include<cstdio> #include<cstring> #include<queue> #define maxn 10001 #define maxm 100009 #ifdef WIN32 #define PLL "%I64d\n" #else #define PLL "%lld\n" #endif using namespace std; struct Edge{ int x,y,nxt; Edge(int x=0,int y=0,int nxt=0): x(x),y(y),nxt(nxt){} }edge[maxm*2]; int head[maxn],col[maxn],q[maxn]; int sumedge,n,m,cnt1,x,y,cnt2,ans; void add(int x,int y){ edge[++sumedge]=Edge(x,y,head[x]); head[x]=sumedge; } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=m;i++){ scanf("%d%d",&x,&y); add(x,y);add(y,x); } memset(col,-1,sizeof(col)); for(int i=1;i<=n;i++){ if(col[i]==-1){ int h,t;h=t=1;col[i]=1;q[h]=i; while(h<=t){ int now=q[h++]; if(col[now]==1)cnt1++; else cnt2++; for(int j=head[now];j;j=edge[j].nxt){ int v=edge[j].y; if(col[v]==-1){ q[++t]=v; col[v]=col[now]^1; } if(col[v]==col[now]){ printf("Impossible"); return 0; } } } } ans+=min(cnt1,cnt2); cnt1=cnt2=0; } printf(PLL,ans); }
二分图判定
四、LCA
#include<iostream> #include<cstdio> #include<cstring> #define maxn 500009 using namespace std; int n,m,s,sumedge; int head[maxn],deep[maxn],size[maxn],dad[maxn],top[maxn]; struct Edge{ int x,y,nxt; Edge(int x=0,int y=0,int nxt=0): x(x),y(y),nxt(nxt){} }edge[maxn<<1]; void add(int x,int y){ edge[++sumedge]=Edge(x,y,head[x]); head[x]=sumedge; } void dfs(int x){ size[x]=1;deep[x]=deep[dad[x]]+1; for(int i=head[x];i;i=edge[i].nxt){ int v=edge[i].y; if(v==dad[x])continue; dad[v]=x;dfs(v); size[x]+=size[v]; } } void dfs_(int x){ int s=0; if(!top[x])top[x]=x; for(int i=head[x];i;i=edge[i].nxt){ int v=edge[i].y; if(v!=dad[x]&&size[v]>size[s])s=v; } if(s){ top[s]=top[x]; dfs_(s); } for(int i=head[x];i;i=edge[i].nxt){ int v=edge[i].y; if(v!=dad[x]&&v!=s)dfs_(v); } } int lca(int x,int y){ for(;top[x]!=top[y];){ if(deep[top[x]]>deep[top[y]])swap(x,y); y=dad[top[y]]; } if(deep[x]>deep[y])return y; return x; } int main(){ scanf("%d%d%d",&n,&m,&s); for(int i=1;i<n;i++){ int x,y; scanf("%d%d",&x,&y); add(x,y);add(y,x); } dfs(s);dfs_(s); for(int i=1;i<=m;i++){ int x,y; scanf("%d%d",&x,&y); printf("%d\n",lca(x,y)); } return 0; }
树剖
#include<iostream> #include<cstdio> #include<cstring> #define maxn 500009 using namespace std; int n,m,s,sumedge; int head[maxn],dad[maxn][25],deep[maxn]; struct Edge{ int x,y,nxt; Edge(int x=0,int y=0,int nxt=0): x(x),y(y),nxt(nxt){} }edge[maxn<<1]; void add(int x,int y){ edge[++sumedge]=Edge(x,y,head[x]); head[x]=sumedge; } void dfs(int x){ deep[x]=deep[dad[x][0]]+1; for(int i=0;dad[x][i];i++) dad[x][i+1]=dad[dad[x][i]][i]; for(int i=head[x];i;i=edge[i].nxt){ int v=edge[i].y; if(v==dad[x][0])continue; dad[v][0]=x; dfs(v); } } int lca(int x,int y){ if(deep[x]>deep[y])swap(x,y); for(int i=20;i>=0;i--)if(deep[dad[y][i]]>=deep[x])y=dad[y][i]; if(x==y)return x; for(int i=20;i>=0;i--)if(dad[x][i]!=dad[y][i])x=dad[x][i],y=dad[y][i]; return dad[x][0]; } int main(){ scanf("%d%d%d",&n,&m,&s); for(int i=1;i<n;i++){ int x,y; scanf("%d%d",&x,&y); add(x,y);add(y,x); } dfs(s); for(int i=1;i<=m;i++){ int x,y; scanf("%d%d",&x,&y); printf("%d\n",lca(x,y)); } return 0; }
倍增
五、tarjan
#include<iostream> #include<cstdlib> #include<algorithm> #include<cstdio> #include<cstring> #define maxn 1000006 int n,m,sumedge,root,ans,tim; int low[maxn],dfn[maxn],iscut[maxn],head[maxn]; struct Edge{ int x,y,nxt; Edge(int x=0,int y=0,int nxt=0): x(x),y(y),nxt(nxt){} }edge[maxn<<1]; void add(int x,int y){ edge[++sumedge]=Edge(x,y,head[x]); head[x]=sumedge; } int min(int x,int y){ return x<y?x:y; } void Tarjian(int x,int fa){ dfn[x]=low[x]=++tim;int cnt=0; for(int i=head[x];i;i=edge[i].nxt){ int v=edge[i].y; if(v==fa)continue; if(dfn[v]==0){ cnt++; Tarjian(v,x); low[x]=min(low[x],low[v]); if(low[v]>=dfn[x]&&x!=root&&iscut[x]==0)iscut[x]=true,ans++; if(x==root&&cnt>=2&&iscut[x]==0)iscut[x]=true,ans++; }else low[x]=min(low[x],dfn[v]); } } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=m;i++){ int x,y; scanf("%d%d",&x,&y); add(x,y);add(y,x); } for(int i=1;i<=n;i++) if(!dfn[i])root=i,Tarjian(i,i); printf("%d\n",ans); for(int i=1;i<=n;i++) if(iscut[i]) printf("%d ",i); return 0; }
割点
#include<iostream> #include<cstdio> #include<cstring> #define maxn 22000 using namespace std; int n,sumedge,sumclr,top,tim,ans; int Stack[maxn],instack[maxn],low[maxn],dfn[maxn],bel[maxn],rd[maxn],head[maxn]; struct Edge{ int x,y,nxt; Edge(int x=0,int y=0,int nxt=0): x(x),y(y),nxt(nxt){} }edge[maxn<<1]; void add(int x,int y){ edge[++sumedge]=Edge(x,y,head[x]); head[x]=sumedge; } void Tarjian(int x){ Stack[++top]=x;instack[x]=true; low[x]=dfn[x]=++tim; for(int i=head[x];i;i=edge[i].nxt){ int v=edge[i].y; if(instack[v])low[x]=min(low[x],dfn[v]); else if(!dfn[v]){ Tarjian(v); low[x]=min(low[x],low[v]); } } if(low[x]==dfn[x]){ sumclr++; while(Stack[top+1]!=x){ bel[Stack[top]]=sumclr; instack[Stack[top]]=false; top--; } } } int main(){ scanf("%d",&n); for(int i=1;i<=n;i++){ int x; while(1){ scanf("%d",&x); if(!x)break; add(i,x); } } for(int i=1;i<=n;i++)if(!dfn[i])Tarjian(i); for(int x=1;x<=n;x++){ for(int i=head[x];i;i=edge[i].nxt){ int v=edge[i].y; if(bel[x]!=bel[v])rd[bel[v]]++; } } for(int i=1;i<=sumclr;i++)if(!rd[i])ans++; printf("%d\n",ans); return 0; } AC
缩点
注意图不一定连通
六、结论/性质
二分图:
1. 最小点覆盖 = 最大匹配。
2. 最大独立集 = 顶点总数 - 最大匹配。
3. 最小边覆盖 = 顶点总数 - 最大匹配。
4. 最小路径覆盖 = 顶点总数 - 最大匹配。
树:
1、图上两点之间的路径的最小边的最大值一定在最大生成树上
2、树的直径:树上最远两点的距离
3、树的重心:
树的重心定义:
树中的一个点,删掉这个点,使得剩下的树所
构成的森林中最大的子树节点数最少。
树的重心推论:
1.设树上的一个点S,树上其余所有点到S点的
距离之和最小,那么S就是重心。
2.树的重心不唯一。
然后可以依靠定义来求树的重心。
首先以任意一个点,进行dfs,dfs过程中统计以
每个点为根的子树中,一共含有多少节点。
然后 总节点数 减去 子树的节点数 减去1(自己),
就是它父亲那边点的数量。做差之后取最小值。
时间: 2024-10-12 18:42:40