ZOJ 2532 Internship

26 篇文章 0 订阅
19 篇文章 0 订阅

ZOJ 2532 Internship

网络流

题意

CIA公司想采用新技术升级网络,在实验测试阶段,他们想升级其中的一段网络以便观察新技术在多大的长度上提升网络的性能,你作为实习生的任务是调查那一段网络能提高CIA总部的宽带。

思路

找割边集。
判断一段网络可不可以提升网络就要看它是不是满流,如果满流则可能在升级后提升CIA总部的宽带,但是如果提升后并不能增广,即不能提升CIA总部的宽带,所以判断一段是不是可提升的则有两个条件:(1)在进行增广后这段网络是满流的,(2)在提升后可以增广。

所以从源DFS一次,标记,从汇DFS一次,标记。再枚举边,判断。

代码

ZOJ上不去,粘的别人的。

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <vector>
#include <algorithm>

using namespace std;

const int INF = 0x3f3f3f3f;

typedef struct node
{

    int u;

    int v;

    int Flow;

    int next;
}Line;

Line Li[2200];

int Head[110],top;

int vis[110],ans[110];

bool vis1[110],vis2[110];

int n,m,l;

int s,t;

void AddEdge(int u,int v,int f)
{
    Li[top].v=v; Li[top].u=u;
    Li[top].Flow=f;
    Li[top].next=Head[u];
    Head[u]=top++;
}

bool BFS()
{
    memset(vis,-1,sizeof(vis));

    vis[s]=0;

    queue<int >Q;

    Q.push(s);

    while(!Q.empty())
    {

        int u=Q.front();

        Q.pop();

        for(int i=Head[u];i!=-1;i=Li[i].next)
        {

            if(Li[i].Flow&&vis[Li[i].v]==-1)
            {
                vis[Li[i].v]=vis[u]+1;

                Q.push(Li[i].v);

            }
        }
    }
    return vis[t]!=-1;

}

int DFS(int u,int f)
{
    if(u==t)
    {
        return f;
    }
    int ans=0;

    for(int i=Head[u];i!=-1;i=Li[i].next)
    {
        if(Li[i].Flow&&vis[Li[i].v]==vis[u]+1)
        {
            int d=DFS(Li[i].v,min(f,Li[i].Flow));
            f-=d;
            Li[i].Flow-=d;
            Li[i^1].Flow+=d;
            ans+=d;
        }
    }
    return ans;
}

void dfs(int u,bool *vist,int op)
{
    vist[u]=true;


    for(int i=Head[u];i!=-1;i=Li[i].next)
    {
        if(!vist[Li[i].v]&&Li[i^op].Flow!=0)
        {
            dfs(Li[i].v,vist,op);
        }
    }
}

void Dinic()//网络流进行增广
{
    int ans;

    while(BFS())
    {
        ans=DFS(s,INF);

    }
}



int main()
{
    while(~scanf("%d %d %d",&n,&m,&l))
    {

        if(n+m+l==0)
        {
            break;
        }

        s=n+m+1;//源点

        t=0;//汇点

        memset(Head,-1,sizeof(Head));

        int a,b,c;

        top = 0;

        for(int i=0;i<l;i++)
        {
            scanf("%d %d %d",&a,&b,&c);
            AddEdge(a,b,c);//建立边,正向为c,负向为0
            AddEdge(b,a,0);
        }

        for(int i=1;i<=n;i++)
        {
            AddEdge(s,i,INF);

            AddEdge(i,s,0);//建立城市与源点之间的边,权值为INF
        }

        Dinic();

        memset(vis1,false,sizeof(vis1));

        memset(vis2,false,sizeof(vis2));

        dfs(s,vis1,0);//从源点向汇点搜索,标记还有剩余流的点

        dfs(t,vis2,1);//从汇点到源点搜索,标记还有剩余流的点

        int num=0;

        for(int i=0;i<l;i++)
        {
            if(Li[i<<1].Flow==0&&vis1[Li[i<<1].u]&&vis2[Li[i<<1].v])
            {
                ans[num++]=i+1;//如果一条边的u与v都被标记,表明s->u,v->t,但是这条边是满流,所以提升这条边。
            }
        }

        if(num)
        {
            for(int i=0;i<num;i++)
            {
                if(i)
                {
                    printf(" ");
                }
                printf("%d",ans[i]);
            }
        }
        printf("\n");

    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值