一些图论模板

1.单源最短路

//Twenty
#include<cstdio>
#include<iostream> 
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
int n,m,maxl=1e9,x,y,s,t,vis[110];
double a[110],b[110],f[110][110],dis[110];
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    cin>>a[i]>>b[i];
    for(int i=1;i<=n;i++)
    for(int j=1;j<=n;j++)
    f[i][j]=maxl;
    scanf("%d",&m);
    for(int i=1;i<=m;i++) {
        scanf("%d%d",&x,&y);
        f[x][y]=f[y][x]=sqrt(pow((a[x]-a[y]),2)+pow((b[x]-b[y]),2));
    }
    scanf("%d%d",&s,&t);
    for(int i=1;i<=n;i++)
    dis[i]=f[s][i];
    dis[s]=0;
    for(int i=1;i<=n;i++) {
     double maxn=1e9;
     int k=0;
     for(int j=1;j<=n;j++)
     if(dis[j]<maxn&&!vis[j]){
           maxn=dis[j];
           k=j;
    }
    if(k==0)break;
    else{
    vis[k]=1;
    for(int j=1;j<=n;j++){
     if(dis[k]+f[k][j]<dis[j])
     dis[j]=dis[k]+f[k][j];
    }
    }  
    }
    printf("%.2lf",dis[t]);
    return 0;
}
dijkstra
//Twenty
#include<cstdio>
#include<iostream> 
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
int n,m,maxl=1e9,x,y,s,t,vis[110];
double a[110],b[110],f[110][110],dis[110];
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    cin>>a[i]>>b[i];
    for(int i=1;i<=n;i++)
    for(int j=1;j<=n;j++)
    f[i][j]=maxl;
    scanf("%d",&m);
    for(int i=1;i<=m;i++){
        scanf("%d%d",&x,&y);
        f[x][y]=f[y][x]=sqrt(pow((a[x]-a[y]),2)+pow((b[x]-b[y]),2));
    }
    scanf("%d%d",&s,&t);    
    for(int k=1;k<=n;k++)
    for(int i=1;i<=n;i++)
    for(int j=1;j<=n;j++)
     if(i!=j&&k!=j&&k!=i&&f[i][k]+f[k][j]<f[i][j])f[i][j]=f[i][k]+f[k][j]; 
    printf("%.2lf",f[s][t]);
    return 0;
}
floyd
//Twenty
#include<cstdio>
#include<iostream> 
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
using namespace std;
const int maxn=500000;
int n,m,s,t,first[maxn],next[maxn],wi[maxn],to[maxn],ecnt=0,dis[maxn],vis[maxn];
int add(int x,int y,int w) {
    next[++ecnt]=first[x];first[x]=ecnt;to[ecnt]=y;wi[ecnt]=w;
    next[++ecnt]=first[y];first[y]=ecnt;to[ecnt]=x;wi[ecnt]=w;
}
int spfa() {
    queue<int>team;
    dis[s]=0;
    vis[s]=1;
    team.push(s);
    while(!team.empty()) {
        int x;
        x=team.front();
        team.pop();
        for(int i=first[x];i!=-1;i=next[i]) {
            if(wi[i]+dis[x]<dis[to[i]]) {
              dis[to[i]]=wi[i]+dis[x];    
              if(!vis[to[i]])
              {vis[to[i]]=1;    
              team.push(to[i]);}    
            }
        }
        vis[x]=0;
    }
    
}

int main()
{
    memset(first,-1,sizeof(first));
    memset(vis,0,sizeof(vis));
    memset(dis,127,sizeof(dis));
    scanf("%d%d%d%d",&n,&m,&s,&t);
    for(int i=1;i<=m;i++) {
        int x,y,w;
        scanf("%d%d%d",&x,&y,&w);
        add(x,y,w);
    }
    spfa();
    printf("%d",dis[t]);
    return 0;
}
SPFA模板

 

2.最小生成树

//Twenty
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<iostream>
using namespace std;
int fa[10000],ans=0,k=0;
struct edge {
    int u,v,w;
}e[1000];
bool cmp(const edge&a,const edge&b) {return a.w>b.w;}
int find(int x) {return x==fa[x]?x:fa[x]=find(fa[x]);}
int main()
{
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=m;i++)
      cin>>e[i].u>>e[i].v>>e[i].w;
    sort(e+1,e+1+m,cmp);
    for(int i=1;i<=n;i++)
    fa[i]=i;
    for(int i=1;i<=m;i++) {
        int u,v;
        u=e[i].u;v=e[i].v;
        u=find(u);v=find(v);
        if(u!=v) {
            ans+=e[i].w;
            fa[u]=v;
            k++;
            if(k==n-1)break;
        }
    }
    cout<<ans<<endl;
    return 0;
}
kruskal
//Twenty
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int ans=0,n,a[150][150],vis[150],dis[150];
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
    for(int j=1;j<=n;j++)
    cin>>a[i][j];
    memset(dis,127,sizeof(dis));
    memset(vis,0,sizeof(vis));
    dis[1]=0;
    for(int i=1;i<=n;i++) {
        int k=0;
        for(int j=1;j<=n;j++)
        if(!vis[j]&&dis[j]<dis[k])
        k=j;
        vis[k]=1;
        for(int j=1;j<=n;j++)
         if(!vis[j]&&dis[j]>a[k][j])
           dis[j]=a[k][j];        
    }
    for(int i=1;i<=n;i++)
    ans+=dis[i];
    cout<<ans<<endl;
    return 0;
}
prim

 

3.dfs_spfa判负环

//Twenty
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
#include<vector>
const int maxn=200000+29;
using namespace std;
int flag,x,y,z,T,n,m,fir[maxn],nxt[maxn<<1],to[maxn<<1],val[maxn<<1],ecnt,vis[maxn],dis[maxn];
void add(int u,int v,int w){
    nxt[++ecnt]=fir[u]; fir[u]=ecnt; to[ecnt]=v; val[ecnt]=w;
}
void dfs_spfa(int x){
    if(vis[x]) {flag=1;return;}
    vis[x]=1;
    for(int i=fir[x];i;i=nxt[i])
        if(dis[to[i]]>val[i]+dis[x]){
            dis[to[i]]=val[i]+dis[x];
            dfs_spfa(to[i]);
            if(flag) return;
        }
    vis[x]=0;
}
int main()
{
   scanf("%d",&T);
   while(T--){
   flag=0;
   scanf("%d%d",&n,&m);
   for(int i=1;i<=m;i++){
       scanf("%d%d%d",&x,&y,&z);
       add(x,y,z);
       if(z>=0) add(y,x,z);
   }
   for(int i=1;i<=n;i++) dis[i]=vis[i]=0;
   for(int i=1;i<=n;i++)
    {dfs_spfa(i);
    if(flag) break;}
   if(flag) printf("YE5\n");
   else printf("N0\n");
   for(int i=1;i<=n;i++) fir[i]=0;
   for(int j=1;j<=ecnt;j++) nxt[j]=to[j]=0;
   ecnt=0;  
   }
   return 0;
}
dfs_spfa判负环

 

4.LCA

//Twenty
#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=2*500000;
int n,n2,n3,a,b;
int first[maxn],next[maxn],to[maxn],vis[maxn],firstarrive[maxn],R[maxn],cur[maxn];
int dp[maxn][20]; 
int ecnt=0;
int add(int u,int v) {
    next[++ecnt]=first[u];first[u]=ecnt;to[ecnt]=v;
    next[++ecnt]=first[v];first[v]=ecnt;to[ecnt]=u;    
}
int cnt=0;
void dfs(int node,int dep) {
    vis[node]=1;
    cur[++cnt]=node;
    R[cnt]=dep;
    firstarrive[node]=cnt;
    for(int i=first[node];i!=-1;i=next[i]) {
        if(!vis[to[i]]) {
            dfs(to[i],dep+1);
            cur[++cnt]=node;
            R[cnt]=dep;
        }
        
    }    
}

void ST(int n) {
    for(int i=1;i<=n;i++)
    dp[i][0]=i;
    for(int j=1;(1<<j)<=n;j++)
    for(int i=1;(i+(1<<j)-1)<=n;i++) {
        int a=dp[i][j-1],b=dp[i+(1<<(j-1))][j-1];
        dp[i][j]=R[a]<R[b]?a:b;
    } 
}
int RMQ(int l,int r) {
    int k=0;
    while(l+(1<<(k+1))-1<=r) {
        k++;
    }
    int a=dp[l][k],b=dp[r-(1<<k)+1][k];
    return R[a]<R[b]?a:b;
}
int LCA(int a,int b) {
    a=firstarrive[a];
    b=firstarrive[b];
    if(a>b)swap(a,b);
    return cur[RMQ(a,b)];
}
int main()
{
    memset(first,-1,sizeof(first));
    scanf("%d%d%d",&n,&n2,&n3);
    for(int i=1;i<n;i++) {
    scanf("%d%d",&a,&b);     
    add(a,b);
    }
    dfs(n3,1);
    ST(2*n);
    while(n2--) {
        scanf("%d%d",&a,&b);
        printf("%d\n",LCA(a,b));
    }
    return 0;
}
RMQ求LCA
//Twenty
#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=5000;
int n,n2,n3,a,b;
int first[maxn],next[maxn],to[maxn],fa[maxn],vis[maxn];
int firstcheck[maxn],nextcheck[maxn],tocheck[maxn];
int ans[maxn][maxn],check[maxn][3];
int dp[maxn][20]; 
int ecnt=0;
int add(int u,int v) {
    next[++ecnt]=first[u];first[u]=ecnt;to[ecnt]=v;
    next[++ecnt]=first[v];first[v]=ecnt;to[ecnt]=u;    
}
int addcheck(int u,int v) {
    nextcheck[++ecnt]=firstcheck[u];firstcheck[u]=ecnt;tocheck[ecnt]=v;
    nextcheck[++ecnt]=first[v];firstcheck[v]=ecnt;tocheck[ecnt]=u;    
}
int find(int x) {return x==fa[x]?x:fa[x]=find(fa[x]);}
int dfs(int node,int far) {
    vis[node]=1;
    for(int i=first[node];i!=0;i=next[i]) {
        if(!vis[to[i]]) {
            dfs(to[i],node);
        }
    }
    fa[node]=far;
    for(int i=firstcheck[node];i!=0;i=next[i]) {
        if(!vis[tocheck[i]])
        continue;
        else ans[tocheck[i]][node]=ans[node][tocheck[i]]=find(tocheck[i]);
    }    
}

int main()
{
    scanf("%d%d%d",&n,&n2,&n3);
    for(int i=1;i<n;i++) {
    scanf("%d%d",&a,&b);     
    add(a,b);
    }
    for(int i=1;i<=n;i++)
    fa[i]=i;
    for(int i=1;i<=n2;i++) {
        cin>>a>>b; 
        check[i][1]=a;
        check[i][2]=b;
        addcheck(a,b);
    }
    dfs(1,1);
    for(int i=1;i<=n2;i++)
        printf("%d\n",ans[check[i][1]][check[i][2]]); 
    return 0;
}
tarjan求LCA
//Twenty
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
#include<vector>
const int maxn=500005;
using namespace std;
int n,q,s,x,y,fir[maxn],next[maxn*2],to[maxn*2],fa[maxn][20],vis[maxn],R[maxn];
int ecnt;
inline int add(int u,int v){
    next[++ecnt]=fir[u];fir[u]=ecnt;to[ecnt]=v;
    next[++ecnt]=fir[v];fir[v]=ecnt;to[ecnt]=u;
}
int dfs(int x,int f) {
    
    vis[x]=1;
    R[x]=R[f]+1;
    fa[x][0]=f;
    for(int i=fir[x];i!=0;i=next[i]) {
        if(!vis[to[i]]) {
            dfs(to[i],x);
        }
    } 
}
void init() {
    for(int j=1;(1<<j)<=n;j++)
    for(int i=1;i<=n;i++)
    {
        if(fa[i][j-1]!=-1)
        fa[i][j]=fa[fa[i][j-1]][j-1];
    }
}
int LCA(int a,int b){
    if(R[a]<R[b]) swap(a,b);
    int i;
    for(i=0;(1<<i)<=R[a];i++);
    i--;
    for(int j=i;j>=0;j--) {
        if(R[a]-(1<<j)>=R[b])
        a=fa[a][j];
    }
    if(a==b) return a;
    for(int j=i;j>=0;j--) {
        if(fa[a][j]!=-1&&fa[a][j]!=fa[b][j]) {
             a=fa[a][j];
             b=fa[b][j];
         }
    }    
    return fa[a][0];
}
int main()
{
   memset(fa,-1,sizeof(fa));
   scanf("%d%d%d",&n,&q,&s);
   for(int i=1;i<n;i++) {
        scanf("%d%d",&x,&y);
        add(x,y);
   }
   dfs(s,s);
   init();
   while(q--) {
       scanf("%d%d",&x,&y);
       printf("%d\n",LCA(x,y));
   }
   return 0;
}
倍增求LCA

 

5.tarjan

//Twenty
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
#include<vector>
#include<stack>
const int maxn=(1e5+299)*2;
using namespace std;
int ecnt,v[maxn],fir[maxn],nxt[maxn],to[maxn],dp[maxn],dfn[maxn],low[maxn];
int clock,nn,xn,m,sccno[maxn],ans;
void add(int x,int y){
    nxt[++ecnt]=fir[x]; fir[x]=ecnt; to[ecnt]=y;
}
stack<int>sta;
void tarjan(int x){
    dfn[x]=low[x]=++clock;
    sta.push(x);
    for(int i=fir[x];i;i=nxt[i]){
        if(!dfn[to[i]]){
            tarjan(to[i]);
            low[x]=min(low[x],low[to[i]]);
        }
        else if(!sccno[to[i]])
            low[x]=min(low[x],dfn[to[i]]);
    }
    if(dfn[x]==low[x])
    {
        xn++;
        for(;;){
           int u=sta.top();
           sta.pop();
           sccno[u]=xn;
           v[xn]+=v[u];
           if(u==x) break;
        }
    }
}
void Dp(int x){
    if(dp[x]) return;
    int now=0;
    for(int i=fir[x];i;i=nxt[i]){
        Dp(to[i]);
        now=max(now,dp[to[i]]);
    }
    dp[x]=v[x]+now;
}
int main()
{
    scanf("%d%d",&nn,&m); 
    xn=nn;
    for(int i=1;i<=nn;i++) scanf("%d",&v[i]);
    for(int i=1;i<=m;i++){
        int x,y;
        scanf("%d%d",&x,&y);
        add(x,y);
    }
    for(int i=1;i<=nn;i++)
        if(!dfn[i]) 
        tarjan(i);    
    for(int i=1;i<=nn;i++)
     for(int j=fir[i];j;j=nxt[j]){
        int u=i,v=to[j];
        if(sccno[u]!=sccno[v])
          add(sccno[u],sccno[v]);
     }
    for(int i=nn+1;i<=xn;i++){
        Dp(i);
        ans=max(ans,dp[i]);
    }
    printf("%d\n",ans);
    return 0;
}
tarjan强连通分量 缩点
//Twenty
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
#include<vector>
const int maxn=(100000+299)*2; 
using namespace std;
int clock,ecnt,n,m,fir[maxn],nxt[maxn],to[maxn],dfn[maxn],low[maxn];
int cut[maxn],ans; 
void add(int x,int y){
    nxt[++ecnt]=fir[x]; fir[x]=ecnt; to[ecnt]=y;
    nxt[++ecnt]=fir[y]; fir[y]=ecnt; to[ecnt]=x;
}
void tarjan(int x,int rt){
    int rc=0;
    dfn[x]=low[x]=++clock;
    for(int i=fir[x];i;i=nxt[i]){
        if(!dfn[to[i]]){
            tarjan(to[i],rt);
            low[x]=min(low[x],low[to[i]]);
            if(low[to[i]]>=dfn[x]&&x!=rt) cut[x]=1;
            if(x==rt) rc++;
        }
        else low[x]=min(low[x],dfn[to[i]]);
    }
    if(x==rt&&rc>=2) cut[x]=1; 
}
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);
    }
    for(int i=1;i<=n;i++)
      if(!dfn[i]) tarjan(i,i);
    for(int i=1;i<=n;i++)
      if(cut[i]) ans++;
    printf("%d\n",ans);
    for(int i=1;i<=n;i++)
     if(cut[i]) printf("%d ",i);
    return 0;
}
tarjan 割点
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
typedef long long LL;
using namespace std;
const int maxn=10000+299;
const int maxm=100000*2+299;
int T,n,m,x,y,fir[maxn],nxt[maxm],to[maxm],fa[maxn],cc,cut[maxm],dfn[maxn],id[maxm],low[maxn],dfs_clock,ecnt;
void add(int x,int y,int tot) { 
    nxt[++ecnt]=fir[x]; fir[x]=ecnt; to[ecnt]=y; id[ecnt]=tot;
    nxt[++ecnt]=fir[y]; fir[y]=ecnt; to[ecnt]=x; id[ecnt]=tot;
}
void clear() {
    memset(fir,0,sizeof(fir));
    memset(dfn,0,sizeof(dfn));
    memset(low,0,sizeof(low));
    memset(cut,0,sizeof(cut));
    memset(fa,0,sizeof(fa)); ecnt=0;
    dfs_clock=0;
}
void tarjan(int x) {
    dfn[x]=low[x]=++dfs_clock;
    for(int i=fir[x];i;i=nxt[i]) {
        if(!dfn[to[i]]) {
            fa[to[i]]=i;
            tarjan(to[i]);
            low[x]=min(low[x],low[to[i]]);
        }
        else if(id[fa[x]]!=id[i]) low[x]=min(low[x],dfn[to[i]]);
    }
    if(fa[x]&&dfn[x]==low[x]) {
        cc++; 
        cut[id[fa[x]]]=1;
    }
}
int main()
{
    scanf("%d",&T);
    while(T) {
        clear();
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++) {
            scanf("%d%d",&x,&y);
            add(x,y,i);    
        }
        for(int i=1;i<=n;i++)
            if(!dfn[i]) tarjan(i);
        printf("%d\n",cc);
        for(int i=1;i<=m;i++) 
            if(cut[i]) { cc--; if(cc) printf("%d ",i); else printf("%d\n",i);}
        --T;
        if(T) printf("\n");
    }
    return 0;
}
tarjan 求桥

 

 

 

 

 

6.拓扑排序

//Twenty
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<queue>
using namespace std;
const int maxn=50000;
const int maxm=2.5*maxn;
int n,m,a,b,ans;
int first[maxn],next[maxm],to[maxm],integ[maxn];
int ecnt=0;
int add(int u,int v){
    next[++ecnt]=first[u];first[u]=ecnt;to[ecnt]=v;}
int toposort(){
    queue<int>team;
    for(int i=1;i<=n;i++){if(integ[i]==0) team.push(i);}
    while(!team.empty() ) {  
       int x=team.front(); team.pop();
       for(int i=first[x];i!=0;i=next[i]){
        integ[to[i]]--;
        if(integ[to[i]]==0)team.push(to[i]);    
      }
    }   
    for(int i=1;i<=n;i++)
      if(integ[i])ans++;
}

int main()
{
    scanf("%d",&n);
    scanf("%d",&m);
    for(int i=1;i<=m;i++) {
        scanf("%d%d",&a,&b);
        integ[b]++;
        add(a,b);
    }
    toposort();
    if(ans==0)printf("o(∩_∩)o");
    else printf("T_T\n%d",ans);
    return 0;
}
奇怪的梦境

 

7.匈牙利算法

#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
#include<vector>
const int maxn=2005;
int n,m,u,v,e,ecnt,ans,fir[maxn],next[maxn*maxn],to[maxn*maxn],f[maxn],pre[maxn];
using namespace std;
void add(int u,int v){
    next[++ecnt]=fir[u];to[ecnt]=v;fir[u]=ecnt;
}
int find(int x){
    for(int i=fir[x];i;i=next[i])
      if(!f[to[i]]){
         f[to[i]]=1;
         if(!pre[to[i]]||find(pre[to[i]])){
             pre[to[i]]=x;
             return 1;
         }
      }
    return 0;
}
int main()
{
   scanf("%d%d%d",&n,&m,&e);
   for(int i=1;i<=e;i++){
      scanf("%d%d",&u,&v);
      if(u<=m&&v<=m) add(u,v+1000);
   } 
   for(int i=1;i<=n;i++){
        memset(f,0,sizeof(f));
     ans+=find(i);
   }
   printf("%d\n",ans);
   return 0;
}
匈牙利

 

posted @ 2017-09-04 19:32  啊宸  阅读(173)  评论(0编辑  收藏  举报