图论总结(持续更新)

来源:互联网 发布:通达信的软件 编辑:程序博客网 时间:2024/06/07 01:50

  • 图论总结
    • 二分图最大匹配
    • km最大权最小权
    • 最大流
    • 最小费用最大流
    • 强联通分量
    • 割点点双联通
    • 割边边双联通
    • 最大团
    • 带权并查集

图论总结

二分图最大匹配

int match[MAXN];bool vis[MAXN];bool dfs(int u){    for(int v = 1; v <= b; ++v)    {        if(!vis[v]&&!tu[u][v])        {            vis[v] = 1;            if(match[v] == -1 || dfs(match[v]))            {                match[v] = u;                return 1;            }        }    }    return 0;}

km最大权最小权

int w[MAXN][MAXN1],pre[MAXN1],kx[MAXN],ky[MAXN1];  bool visx[MAXN1],visy[MAXN1];  void init()  {      memset(ky,0,sizeof(ky));      memset(pre,-1,sizeof(pre));      for(int i=0; i<n; ++i)      {          kx[i]=w[i][0];          for(int j=1; j<m; ++j)          {              kx[i]=max(kx[i],w[i][j]);          }      }  }  bool dfs(int u)  {      visx[u]=1;      for(int i=0; i<m; ++i)      {          if(!visy[i])          {              int t=kx[u]+ky[i]-w[u][i];              if(!t)              {                  visy[i]=1;                  if(pre[i]==-1||dfs(pre[i]))                  {                      pre[i]=u;                      return 1;                  }              }              else d=min(d,t);          }      }      return 0;  }  int km()  {      for(int i=0; i<n; ++i)      {          while(1)          {              memset(visx,0,sizeof(visx));              memset(visy,0,sizeof(visy));              d=inf;              if(dfs(i))break;              for(int j=0; j<m; ++j)              {                  if(visx[j])kx[j]-=d;                  if(visy[j])ky[j]+=d;              }          }      }      int ans=0;      for(int i=0; i<m; ++i)      {          if(pre[i]!=-1)ans+=w[pre[i]][i];      }      return -ans;  }  

最大流

struct node  {      int u,v,f;      int next;  } edge[MAXN*520];  int head[MAXN];  int cnt;  void add(int u,int v,int f)  {      edge[cnt].u=u;      edge[cnt].v=v;      edge[cnt].f=f;      edge[cnt].next=head[u];      head[u]=cnt++;      edge[cnt].u=v;      edge[cnt].v=u;      edge[cnt].f=0;      edge[cnt].next=head[v];      head[v]=cnt++;  }  int dis[MAXN];  int bfs(int s,int t)  {      int u, v ;      memset(dis,-1,sizeof(dis));      dis[s] = 0 ;      queue<int>q;      q.push(s) ;      while( !q.empty() )      {          u = q.front();          q.pop();          for(int i = head[u] ; i != -1 ; i = edge[i].next)          {              v = edge[i].v ;              if( dis[v] == -1 && edge[i].f )              {                  dis[v] = dis[u] + 1 ;                  q.push(v) ;              }          }      }      if( dis[t] > 0 )          return 1 ;      return 0 ;  }  int dfs(int s,int t,int min1)  {      if( s == t )          return min1 ;      int  flow, ans = 0 ;      for(int i = head[s] ; i != -1 ; i = edge[i].next)      {          int v = edge[i].v ;          if( dis[v] == dis[s] + 1 && edge[i].f && (flow = dfs(v,t,min(min1,edge[i].f) ) ) )          {              edge[i].f -= flow ;              edge[i^1].f += flow ;              ans += flow ;              min1 -= flow ;              if( !min1 )                  break;          }      }      if( ans )          return ans ;      dis[s] = -1 ;      return 0;  }  int getMaxFlow()  {      int maxFlow=0,flow;      while(bfs(s,e))      {          while((flow=dfs(s,e,inf))>0)              maxFlow+=flow;      }      return maxFlow;  } 

最小费用最大流

int cnt,head[MAXN];  struct node  {      int u,v,w,f,next;  } edge[8000];  void init()  {      cnt=0;      for(int i=0; i<=e; ++i)head[i]=-1;}  void add(int u,int v,int w,int f)  {      edge[cnt].u=u;      edge[cnt].v=v;      edge[cnt].w=w;      edge[cnt].f=f;      edge[cnt].next=head[u];      head[u]=cnt++;      edge[cnt].u=v;      edge[cnt].v=u;      edge[cnt].w=-w;      edge[cnt].f=0;      edge[cnt].next=head[v];      head[v]=cnt++;  }  bool vis[MAXN];  int dis[MAXN],pre[MAXN];  bool spfa()  {      int i;      for(i=0; i<=e; ++i)      {          dis[i]=inf;          pre[i]=-1;          vis[i]=0;      }      queue<int>q;      q.push(0);      dis[0]=0;      while(!q.empty())      {          int u=q.front();          q.pop();          vis[u]=0;          for(i=head[u]; i!=-1; i=edge[i].next)          {              int v=edge[i].v;              int w=edge[i].w;              int f=edge[i].f;              if(f>0&&dis[v]>dis[u]+w)              {                  dis[v]=dis[u]+w;                  pre[v]=i;                  if(!vis[v])                  {                      vis[v]=1;                      q.push(v);                  }              }          }      }      if(pre[e]==-1)return 0;      return 1;  }  int get_mincost()  {      int max_flow=0,min_cost=0;      while(spfa())      {          int p=pre[e];          int flow=inf;          while(p!=-1)          {              flow=min(flow,edge[p].f);              p=pre[edge[p].u];          }          max_flow+=flow;          min_cost+=flow*dis[e];          p=pre[e];          while(p!=-1)          {              edge[p].f-=flow;              edge[p^1].f+=flow;              p=pre[edge[p].u];          }      }      return min_cost;  }  

强联通分量

vector<int>head[MAXN],G[MAXN];  int dfn[MAXN],sccno[MAXN],sum[MAXN],dfs_clock,scc_cnt;  stack<int>S;  int dfs(int u)  {      int lowu=dfn[u]=++dfs_clock;      S.push(u);      for(int i=0,l=head[u].size(); i<l; ++i)      {          int v=head[u][i];          if(!dfn[v])          {              int lowv=dfs(v);              lowu=min(lowu,lowv);          }          else if(!sccno[v])          {              lowu=min(lowu,dfn[v]);          }      }      if(lowu==dfn[u])      {          scc_cnt++;          while(1)          {              int x=S.top();              S.pop();              sccno[x]=scc_cnt;              if(x==u)break;          }      }      return lowu;  }  void find_scc()  {      dfs_clock=scc_cnt=0;      fill(dfn+1,dfn+1+n,0);      fill(sccno+1,sccno+1+n,0);      for(int i = 1; i <= n; ++i)if(!dfn[i])dfs(i);  }  

割点点双联通

struct Edge  {      int u,v;      Edge(int x,int y)      {          u=x;          v=y;      }  };  //查找双联通分量  int pre[MAXN],bccno[MAXN],iscut[MAXN],sum[MAXN],dfs_clock,bcc_cnt;  vector<int>G[MAXN],bcc[MAXN];  stack<Edge>S;  int dfs(int u,int fa)  {      int lowu=pre[u]=++dfs_clock;      int child=0,l=G[u].size();      for(int i=0; i<l; ++i)      {          int v=G[u][i];          Edge e=Edge(u,v);          if(!pre[v])          {              S.push(e);              child++;              int lowv=dfs(v,u);              lowu=min(lowu,lowv);              if(lowv>=pre[u])              {                  iscut[u]=1;                  bcc_cnt++;                  while(1)                  {                      Edge x=S.top();                      S.pop();                      if(bccno[x.u]!=bcc_cnt)                      {                          bccno[x.u]=bcc_cnt;                          sum[x.u]++;                      }                      if(bccno[x.v]!=bcc_cnt)                      {                          bccno[x.v]=bcc_cnt;                          sum[x.v]++;                      }                      if(x.u==u&&x.v==v)break;                  }              }          }          else if(pre[u]>pre[v]&&v!=fa)          {              S.push(e);              lowu=min(lowu,pre[v]);          }      }      if(fa<0&&child==1)iscut[u]=0;      return lowu;  }  void find_bcc()  {      int i;      for(i=1; i<=n; ++i)      {          pre[i]=bccno[i]=iscut[i]=sum[i]=0;      }      bcc_cnt=dfs_clock=0;      for(i=1; i<=n; ++i)if(!pre[i])dfs(i,-1);  }  

割边边双联通

int dfn[MAXN],bccno[MAXN],bridge[MAXN][MAXN],dfs_clock,bcc_cnt;  int dfs(int u,int fa)  {      int lowu=dfn[u]=++dfs_clock;      for(int i=0,l=G[u].size(); i<l; ++i)      {          int v=G[u][i];          if(!dfn[v])          {              int lowv=dfs(v,u);              lowu=min(lowu,lowv);              if(lowv>dfn[u])              {                  bridge[u][v]=bridge[v][u]=1;              }          }          else if(dfn[u]>dfn[v]&&v!=fa)          {              lowu=min(lowu,dfn[v]);          }      }      return lowu;  }  void find_bridge()  {      for(int i=0; i<n; ++i)      {          dfn[i]=0;          bccno[i]=0;          for(int j=i+1; j<n; ++j)bridge[i][j]=bridge[j][i]=0;      }      dfs_clock=bcc_cnt=0;      for(int i=0; i<n; ++i)if(!dfn[i])dfs(i,-1);  }  int vis[MAXN];  void dfse(int u,int x)  {      bccno[u]=x;      vis[u]=1;      for(int i=0,l=G[u].size(); i<l; ++i)      {          int v=G[u][i];          if(!vis[v]&&!bridge[u][v])          {              dfse(v,x);          }      }  }  void find_bcc()  {      for(int i=0; i<n; ++i)vis[i]=0;      for(int i=0; i<n; ++i)if(!vis[i])dfse(i,++bcc_cnt);  }  

最大团

#include<cstdio>#include<cstring>#define N 1010bool flag[N], a[N][N];int ans, cnt[N], group[N], n, vis[N];// 最大团: V中取K个顶点,两点间相互连接// 最大独立集: V中取K个顶点,两点间不连接 // 最大团数量 = 补图中最大独立集数bool dfs( int u, int pos ){    int i, j;    for( i = u+1; i <= n; i++){        if( cnt[i]+pos <= ans ) return 0;        if( a[u][i] ){             // 与目前团中元素比较,取 Non-N(i)             for( j = 0; j < pos; j++ ) if( !a[i][ vis[j] ] ) break;             if( j == pos ){     // 若为空,则皆与 i 相邻,则此时将i加入到 最大团中                 vis[pos] = i;                if( dfs( i, pos+1 ) ) return 1;                }            }    }        if( pos > ans ){            for( i = 0; i < pos; i++ )                group[i] = vis[i]; // 最大团 元素             ans = pos;            return 1;        }        return 0;} void maxclique(){    ans=-1;    for(int i=n;i>0;i--)    {        vis[0]=i;        dfs(i,1);        cnt[i]=ans;    }}

带权并查集

int findx(int x)  {      if(pre[x]==x)      {          return x;      }      int order=pre[x];      pre[x]=findx(pre[x]);      relation[x]=(relation[x]+relation[order])%2;      return pre[x];  }  if(a!=b)//关系还没有建立过          {              puts("YES");              //更新结点值              pre[b]=a;              relation[b]=(relation[x]-relation[y]+z+2)%2;          }          else//关系已经建立          {              int p=(relation[x]-relation[y]+2)%2;//得到关系              if(p==z)puts("YES");              else puts("NO");          }  
原创粉丝点击