簡談圖論重要性&&圖論總結

從外地學習回來,我對圖論纔有認識(之前就沒接觸過,很是尷尬),說實話,學好圖論的重要性,就像學數學時在進行解析幾什麼時候,圖極有多是打開答案的最後祕鑰,也就是數形結合,而懂的人永遠明白,用圖解決絕對比用解析簡單(通常狀況)。而圖論對於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; }

 

  以後還有許多基礎性的知識在之後會看到。

相關文章
相關標籤/搜索