图论相关(更新5.31)

来自AOJ GRL Graph Algorithm切题

部分来自上交红书


SPFA 单源最短路

int r, v, e, x, y, d;
int dist[MAXN];
bool inque[MAXN];
queue<int> que;

vector<pair<int,int> > g[MAXN];

void spfa()
{
    memset(dist,0x3f,sizeof dist);
    dist[r]=0;
    while(!que.empty()) que.pop();
    que.push(r);
    inque[r]=true;
    while(!que.empty()){
        int u=que.front();
        que.pop();
        int sz=g[u].size();
        For(i,0,sz){
            if(dist[u]+g[u][i].second<dist[g[u][i].first]){
                dist[g[u][i].first]=dist[u]+g[u][i].second;
                if(!inque[g[u][i].first]){
                    inque[g[u][i].first]=true;
                    que.push(g[u][i].first);
                }
            }
        }
        inque[u]=false;
    }
}

int main()
{
    scanf("%d%d%d",&v,&e,&r);
    For(i,0,e){
        scanf("%d%d%d",&x,&y,&d);
        g[x].push_back(make_pair(y,d));
    }
    spfa();
    For(i,0,v){
        if(dist[i]==0x3f3f3f3f) puts("INF");
        else printf("%d\n",dist[i]);
    }
    return 0;
}

SPFA 单源最短路(有负边权和负圈)

int v, e, x, y, d;
LL dist[MAXN][MAXN];
int cnt[MAXN];
bool inque[MAXN][MAXN];
queue<int> que;

vector<pair<int,int> > g[MAXN];

bool spfa()
{
    For(i,0,v) For(j,0,v) dist[i][j]=LONG_LONG_MAX;
    For(r,0,v){
        dist[r][r]=0;
        memset(cnt,0,sizeof cnt);
        while(!que.empty()) que.pop();
        que.push(r);
        inque[r][r]=true;
        while(!que.empty()){
            int u=que.front();
            que.pop();
            int sz=g[u].size();
            For(i,0,sz){
                int id=g[u][i].first;
                if(dist[r][u]+g[u][i].second<dist[r][id]){
                    dist[r][id]=dist[r][u]+g[u][i].second;
                    if(!inque[r][id]){
                        cnt[id]++;
                        if(cnt[id]>e) return false;
                        inque[r][id]=true;
                        que.push(id);
                    }
                }
            }
            inque[r][u]=false;
        }
    }
    return true;
}

int main()
{
    scanf("%d%d",&v,&e);
    For(i,0,e){
        scanf("%d%d%d",&x,&y,&d);
        g[x].push_back(make_pair(y,d));
    }
    if(spfa()){
        For(i,0,v) For(j,0,v){
            if(dist[i][j]==LONG_LONG_MAX) printf("INF%c",j==v-1?'\n':' ');
            else printf("%lld%c",dist[i][j],j==v-1?'\n':' ');
        }
    }
    else puts("NEGATIVE CYCLE");
    return 0;
}



dfs 判环(1有环2无环)

dfs中第二个判断末尾若将r节点加入L队列即为topo排序

int v, e, x, y;
int inque[MAXN];
bool flag=false;
 
vector<int> g[MAXN];
 
void dfs(int r)
{
    if(inque[r]==1){
        flag=true;
    }
    if(!inque[r]){
        inque[r]=1;
        int sz=g[r].size();
        For(i,0,sz) dfs(g[r][i]);
        inque[r]=-1;
    }
}
 
int main()
{
    scanf("%d%d",&v,&e);
    For(i,0,e){
        scanf("%d%d",&x,&y);
        g[x].push_back(y);
    }
    For(i,0,v){
        if(!inque[i]) dfs(i);
        if(flag) break;
    }
    printf("%d\n",flag);
    return 0;
}


prim

int x, y, v, e;
LL d, ans;
LL dist[MAXN];
bool vis[MAXN];

vector<pair<int,LL> > g[MAXN];

LL prim()
{
    memset(vis,0,sizeof vis);
    ans=0;
    For(i,0,v) dist[i]=LONG_LONG_MAX;
    dist[0]=0;
    For(i,0,v){
        int mark=-1;
        For(j,0,v){
            if(!vis[j]){
                if(mark==-1) mark=j;
                else if(dist[j]<dist[mark]) mark=j;
            }
        }
        if(mark==-1) break;
        vis[mark]=true;
        ans+=dist[mark];
        int sz=g[mark].size();
        For(j,0,sz){
            int u=g[mark][j].first;
            if(!vis[u]){
                dist[u]=min(dist[u],g[mark][j].second);
            }
        }
    }
    return ans;
}

int main()
{
    scanf("%d%d",&v,&e);
    For(i,0,e){
        scanf("%d%d%lld",&x,&y,&d);
        g[x].push_back(make_pair(y,d));
        g[y].push_back(make_pair(x,d));
    }
    printf("%lld\n",prim());
    return 0;
}



kruscal

int x, y, v, e, tot;
LL d, ans;
int father[MAXN];

struct edge{
    int from, to, w;
    edge(int from=0, int to=0, int w=0): from(from),to(to),w(w) {}
}g[MAXN];

int cmp(edge a, edge b)
{
    return a.w<b.w;
}

void addedge(int x, int y, int w)
{
    g[tot].from=x, g[tot].to=y, g[tot].w=w; tot++;
    g[tot].from=x, g[tot].to=y, g[tot].w=w; tot++;
}

int getfather(int x)
{
    if(father[x]==x) return x;
    else return father[x]=getfather(father[x]);
}

LL kruscal()
{
    sort(g,g+tot,cmp);
    int cnt=v;
    ans=0;
    For(i,0,v) father[i]=i;
    For(i,0,tot){
        int t1=getfather(g[i].from);
        int t2=getfather(g[i].to);
        if(t1!=t2){
            father[t1]=father[t2];
            ans+=g[i].w;
            if(cnt==1) break;
        }
    }
    return ans;
}

int main()
{
    scanf("%d%d",&v,&e);
    tot=0;
    For(i,0,e){
        scanf("%d%d%lld",&x,&y,&d);
        addedge(x,y,d);
    }
    printf("%lld\n",kruscal());
    return 0;
}


最小树形图

int x, y, v, e, tot, r;
double d, sum;
double g[MAXN][MAXN];
int more, que[MAXN], eg[MAXN];
bool pass[MAXN], used[MAXN];


inline void combine(int id, double &sum)
{
    int tot=0, from;
    for(;id!=0&&!pass[id];id=eg[id]){
        que[tot++]=id;
        pass[id]=true;
    }
    for(from=0;from<tot&&que[from]!=id;++from);
    if(from==tot) return;
    more=1;
    For(i,from,tot){
        sum+=g[eg[que[i]]][que[i]];
        if(i!=from){
            used[que[i]]=true;
            For(j,1,v+1) if(!used[j]){
                g[id][j]=min(g[id][j],g[que[i]][j]);
            }
        }
    }
    For(i,1,v+1) if(!used[i]&&i!=id){
        For(j,from,tot){
            int k=que[j];
            g[i][id]=min(g[i][id],g[i][k]-g[eg[k]][k]);
        }
    }
}


double mdst(int root)
{
    sum=0;
    memset(used,0,sizeof used);
    for(more=1;more;){
        more=0;
        memset(eg,0,sizeof eg);
        For(i,1,v+1){
            if(!used[i]&&i!=root){
                int k=0;
                For(j,1,v+1){
                    if(!used[j]&&j!=i){
                        if(k==0||g[j][i]<g[k][i])
                            k=j;
                    }
                }
                eg[i]=k;
            }
        }
        memset(pass,0,sizeof pass);
        For(i,1,v+1){
            if(!used[i]&&!pass[i]&&i!=root)
                combine(i,sum);
        }
    }
    For(i,1,v+1) if(!used[i]&&i!=root) sum+=g[eg[i]][i];
    return sum;
}


int main()
{
    scanf("%d%d%d",&v,&e,&r);
    For(i,0,e){
        scanf("%d%d%lf",&x,&y,&d);
        g[x+1][y+1]=d;
    }
    printf("%.0lf\n",mdst(r+1));
    return 0;
}


查找桥和关节点(割点)

int v, e, x, y;
int vis[MAXN], low[MAXN], dfn[MAXN];
bool cut[MAXN], bridge[MAXN][MAXN];

vector<int> g[MAXN];

void cut_bridge(int cur, int father, int dep, int n)
{
    vis[cur]=1; dfn[cur]=low[cur]=dep;
    int children=0;
    int sz=g[cur].size();
    For(i,0,sz){
        int u=g[cur][i];
        if(u!=father&&vis[u]==1){
            if(dfn[u]<low[cur])
                low[cur]=dfn[u];
        }
        if(!vis[u]){
            cut_bridge(u,cur,dep+1,n);
            children++;
            if(low[u]<low[cur]) low[cur]=low[u];
            if(father==-1&&children>1||father!=-1&&low[u]>=dfn[cur]) cut[cur]=true;
            if(low[u]>dfn[cur]) bridge[cur][u]=bridge[u][cur]=true;
        }
    }
    vis[cur]=2;
}

int main()
{
    scanf("%d%d",&v,&e);
    For(i,0,e){
        scanf("%d%d",&x,&y);
        g[x].push_back(y);
        g[y].push_back(x);
    }
    cut_bridge(0,-1,0,v);
    For(i,0,v) if(cut[i]) printf("%d\n",i);
    return 0;
}




前向星建图

struct graph{
    typedef vector<int> vi;
    vi info, next, to;
    graph(int n=0, int m=0): to(0), next(0) {
        info.resize(n);
        next.reserve(m);
        to.reserve(m);
    }

    int edge_size(){        //返回边的数量
        return to.size();
    }
    int vertex_size(){      //返回值为最大点的编号-1
        return info.size();
    }
    void expand(int i){
        if(info.size()<i+1)
            info.resize(i+1);
    }
    void add(int i, int j){  //添加一条i到j的边
        expand(i), expand(j);
        to.push_back(j);
        next.push_back(info[i]);
        info[i]=to.size()-1;
    }
    void del_back(){         //删除最后一次添加的边
        int i;
        for(int i=0; i<info.size(); i++){
            if(info[i]==to.size()-1){
                info[i]=next.back();
                break;
            }
        }
        to.pop_back();
        next.pop_back();
    }
    void clear(){            //清空
        info.clear();
        next.resize(0);
        to.resize(0);
    }
};





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值