zoj 2532(Internship )找割边

  题目大意就是给你n个城市,m个中转站,以及l条道路,l条道路描述了n个城市(编号为1到n),m个中转站(编号为n+1到n+m)和总中心(视为编号为0的点)的边关系,然后问你增加哪条边的容量可以增加总中心接受到的数据量。

首先设总中心0为超级汇点et(因为它接受信息),然后设个超级源点st(N+M+1),超级源点就是发出数据的点,因为题目说了每个城市可以看作有无限的数据要发送,所以将每个城市和源点连起来,容量为inf。然后很明显这题就是要找割边,我的理解是割边就是流量满了即残留已经为0的边,并且从st可以到这条边的一个点,从et可以到这条边的另外一个点,那么给这条边增加容量就可以 增大最大流了。做法就是先跑个dinic,目的是得到在最大流情况下的残量网络,然后在此基础上从st往et方向dfs,标记从st点出发能到的点,接着从et往st方向dfs,标记从et点出发能到的点,最后遍历每个正边判断一下是否是割边即可。

这题我因为没有给en初始化,每次交都Segmentation Fault,心累,最后还是逐个语句排除才找到的bug

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
#define inf 0x3f3f3f3f
struct edge
{
    int u,v,cap,nxt;
}e[5500];
int head[500],depth[500],vis1[500],vis2[500],cur[500],ans[5000],que[500];
int n,m,l,st,et,en;
void addedge(int u,int v,int c)
{
    e[en].u=u;
    e[en].v=v;
    e[en].cap=c;
    e[en].nxt=head[u];
    head[u]=en++;
    e[en].u=v;
    e[en].v=u;
    e[en].cap=0;
    e[en].nxt=head[v];
    head[v]=en++;
}
bool bfs()
{
    int fron,rear;
    fron=rear=0;
    for(int i=et;i<=st;i++)
        depth[i]=0;
    depth[st]=1;
    que[rear++]=st;
    while(fron!=rear)
    {
        int u=que[fron++];
        for(int i=head[u];i!=-1;i=e[i].nxt)
        {
            if(e[i].cap&&!depth[e[i].v])
            {
                depth[e[i].v]=depth[u]+1;
                que[rear++]=e[i].v;
            }
        }
    }
    return depth[et]!=0;

}
int dfs(int u,int f)
{
    if(u==et) return f;
    for(int&i=cur[u];i!=-1;i=e[i].nxt)
    {
        if((depth[e[i].v]==depth[u]+1)&&e[i].cap)
        {
            int ff=dfs(e[i].v,min(f,e[i].cap));
            if(ff>0)
            {
                e[i].cap-=ff;
                e[i^1].cap+=ff;
                return ff;
            }
        }
    }
    return 0;
}
void dinic()
{
    int maxflow=0;
    while(bfs())
    {
        for(int i=et;i<=st;i++)
            cur[i]=head[i];
        int tmp;
        while(tmp=dfs(st,inf))
            maxflow+=tmp;


    }
}
void dfs1(int u)
{
    vis1[u]=1;
    for(int i=head[u];i!=-1;i=e[i].nxt)
    {
        int v=e[i].v;
        if(!vis1[v]&&e[i].cap)
            dfs1(v);
    }
}
void dfs2(int u)
{
    vis2[u]=1;
    for(int i=head[u];i!=-1;i=e[i].nxt)
    {
        if(!vis2[e[i^1].u]&&e[i^1].cap)
            dfs2(e[i^1].u);

    }
}
int main()
{
    std::ios::sync_with_stdio(false);
    while(1)
    {
        cin>>n;
        if(!n) break;
        cin>>m>>l;
        et=0;
        st=n+m+1;
        for(int i=et;i<=st;i++)
            head[i]=-1;
        en=0;
        for(int i=1;i<=l;i++)//建图
        {
            int uu,vv,cc;
            cin>>uu>>vv>>cc;
            addedge(uu,vv,cc);
        }
        for(int i=1;i<=n;i++)//将源点和每个城市相连,不用对汇点操作,因为汇点才输入的时候就操作完了
            addedge(st,i,inf);
        dinic();
        memset(vis1,0,sizeof(vis1));
        memset(vis2,0,sizeof(vis2));
        dfs1(st);
        dfs2(et);
        int k=0;
        for(int i=0;i<en;i+=2)
        {
            int u=e[i].u;
            int v=e[i].v;
            int c=e[i].cap;
            if((vis1[u]==1)&&(vis2[v]==1)&&(c==0))
                ans[k++]=i/2+1;

        }
        if(k==0)
            cout<<endl;
        else
        {
            cout<<ans[0];
            for(int i=1;i<k;i++)
                cout<<" "<<ans[i];
            cout<<endl;
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_40642465/article/details/81392966
ZOJ