简谈图论重要性&&图论总结

从外地学习回来,我对图论才有认识(之前就没接触过,很是尴尬),说实话,学好图论的重要性,就像学数学时在进行解析几什么时候,图极有多是打开答案的最后秘钥,也就是数形结合,而懂的人永远明白,用图解决绝对比用解析简单(通常状况)。而图论对于oi选手说,就是一大杀器,有可能利己,也可能抱憾终身。因此说图论的重要性就很显然了。node

 

你们在进入图论的时候,应该先掌握链式前向星建图,固然也能够叫邻接表,先附上我喜欢的模板c++

struct node{ int next,to,w; }edge[maxn<<4]; int head[maxn],cent; void add(int u,int v,int w){ edge[++cent]=(node){head[u],v,w}; head[u]=cent; }

  

  ——所谓模板,也就是本身喜欢的颜色涂上而已。算法

 

  固然还有一些其余知识,好比说vector建图,这种建图的方式优势是难度小,并且还能够排序,这个在NOIP2018的D2T1上有极大优点。网络

scan(a),scan(b); vec[a].push_back(b); vec[b].push_back(a);

  而后只要简单地定义排序一下,便可用食。学习

  还有树形dp,这在树形图中将是一大助力,这里是dp求直径。spa

void dp(int s,int fa){ for(int i=head[s];i;i=edge[i].next){ int y=edge[i].to; if(vi[y]) continue; if(y==fa) continue; dp(y,s); an=max(anx,root[x]+root[y]+edge[i].w); root[s]=max(root[s],root[y]+edge[i].w); } }

  在入门以后,请仔细思考与总结rest

  总结方法:code

  1. 反向建边 例题blog

  2. 路径记数,加法原理,并加上限制条件 例题排序

  3. 巧妙运用二分图的检验 例题

  4. 学习二分图的技巧,学会在只有两种条件有关系时,转化成二分图 例题

  5. 深入理解floyd的逐个点处理 例题

  6. 二分答案对于路径长度和其余条件的单调性处理 如4中例题

  7. 分清SPFA(没死透)和Dij二者各自的优点,注意负环

  8. 在最小生成树中,注意prim和kruskal各自的优点 例题1 例题2

  9. 差分约束 SPFA的独特优点(牢记系统约束) 例题

  10. 在连通性中巧用度(即入度和出度) 例题

  11. 善于建超级原点

  (欢迎评价添加)

  拓展性模板

  在二分图中,匈牙利算法虽好,可是毕竟抵不过网络流作法,这里是dinic模板

#include<bits/stdc++.h>
#define maxn 10008
using namespace std; int n,m,head[maxn],s,t,cent=1,d[maxn],maxflow; int min(int a,int b){return a<b?a:b;} const int inf=1<<30; struct node{ int next,to,w; }edge[maxn<<5]; queue<int >q; void add(int u,int v,int w){ edge[++cent]=(node){head[u],v,w};head[u]=cent; edge[++cent]=(node){head[v],u,0};head[v]=cent; } bool bfs(){ memset(d,0,sizeof d); while(q.size()) q.pop(); q.push(s),d[s]=1; while(!q.empty()){ int x=q.front();q.pop(); for(int i=head[x];i;i=edge[i].next){ int y=edge[i].to; if(edge[i].w&&!d[y]){ q.push(y);d[y]=d[x]+1; if(y==t) return 1; } } } return 0; } int Dinic(int x,int flow){ if(x==t) return flow; int rest=flow,k,y; for(int i=head[x];i;i=edge[i].next){ if(edge[i].w&&d[y=edge[i].to]==d[x]+1){ k=Dinic(y,min(rest,edge[i].w)); edge[i].w-=k; edge[i^1].w+=k; rest-=k; } } return flow-rest; } int main(){ scanf("%d%d%d%d",&n,&m,&s,&t); for(int i=1,a,b,w;i<=m;i++){ scanf("%d%d%d",&a,&b,&w); add(a,b,w); } int flow=0; while(bfs()) while(flow=Dinic(s,inf)) maxflow+=flow; printf("%d",maxflow); }

  

  缩点

  在联通性中,缩点是必要的

#include<bits/stdc++.h>
#define maxn 10007
using namespace std; int n,m,head[maxn],a[maxn],cent,stackk[maxn],cnt,tot[maxn],col[maxn]; int dfn[maxn],low[maxn],t,vis[maxn],top,root[maxn],ans; inline int max(int a,int b){return a>b?a:b;} inline int min(int a,int b){return a<b?a:b;} struct node{ int next,to,from; }edge[maxn<<5]; void add(int u,int v){ edge[++cent]=(node){head[u],v,u};head[u]=cent; } void Tarjan(int x){ dfn[x]=low[x]=++t;vis[x]=1; stackk[++top]=x; for(int i=head[x];i;i=edge[i].next){ int y=edge[i].to; if(!dfn[y]){ Tarjan(y); low[x]=min(low[x],low[y]); }else if(vis[y]) low[x]=min(low[x],dfn[y]); } if(low[x]==dfn[x]){ cnt++;int z; do{ z=stackk[top--]; col[z]=cnt; vis[z]=0; tot[cnt]+=a[z]; }while(z!=x); } } void dp(int x,int fa){ root[x]=tot[x];int ol=0; for(int i=head[x];i;i=edge[i].next){ int y=edge[i].to; if(y==fa) continue; dp(y,x); ans=max(ans,root[y]+root[x]); ol=max(ol,root[y]); } root[x]+=ol; } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=1,a,b;i<=m;i++){ scanf("%d%d",&a,&b); add(a,b); } for(int i=1;i<=n;i++){ if(!dfn[i]) Tarjan(i); } memset(head,0,sizeof(head)); for(int i=1;i<=m;i++){ int x=edge[i].from,y=edge[i].to; if(col[x]!=col[y]){ add(col[x],col[y]); } } for(int i=1;i<=cnt;i++){ if(root[i]) continue; dp(i,0); ans=max(root[i],ans); } printf("%d",ans); return 0; }

 

  以后还有许多基础性的知识在之后会看到。

相关文章
相关标签/搜索