hdu 3251 Being a Hero

    这道题目是一道最小割,弱弱的建图还是想了很久,其实建图很简单,只需要把可以取到的点连到一个超级汇点上,容量是那个城市的价值,这样求完最小割就可以保证从源点到汇点无通路,一种情况是,城市选取,道路被隔断,还有一种情况是城市被割掉了。这道题还要去求出任意一个割集。

    之前虽然网络流学了一段时间,发现对算法原理上的东西理解还是太不透彻,刚开始自己的做法就是,因为在最大流跑完之后,原来加入的那些道路相当于是就被堵塞了,所以就砸残留网络里面的那些正向边上进行dfs,自己试了几个例子都没问题,返回WA,纠结很久,实在没有办法改成了直接在残留网络上进行dfs,结果ac,仔细想了一想,前面的想法其实不太对,反向边是必须考虑的,举个例子可以知道,黑色的是增广路径,如果不考虑反向边,C无法染色,D无法染色,点集就分成AB 和CD两个,那么割集就存

在AC和BD两条割边,如果考虑反向边就不会出现这种情况了,割边只有一条BD。

 

 

因为最开始的想法是最小割把点集分成了两部分,但是无形中就把残留网络和最小割直接等价起来了, 其实不对,所以这个地方必须去考虑反向边,另外一方面,isap以及ek在求增广路径的时候也是同个整个残留网络流求解的,这也就是说isap在最后一次寻找增广路径时没有办法到达汇点t,也就是说明了在残留网络中点集分成了两个集合。

 

整理一下思路,这道题先跑最大流,在残留网络中,从源点开始dfs,把能到达的点开始染色,如上图,然后剩下的正向边中如果起点是染色的,终点未染色,那么就是一条割边。

 

代码就贴一部分关键的吧。

 

void dfs(int x)
{
    int tem;
    if(1 == hash[x])
    {    
        return ;
    }
    hash[x]=1;
    tem=net[x];
    while(-1 != tem)
    {
        if(0 == edge[tem].cap)
        {
            tem=edge[tem].next;
            continue;    
        }
        dfs(edge[tem].v);
        tem=edge[tem].next;
    }
}

void print()
{
    int tem,i,sum=0;
    for(i=1;i<=nn;i++)
    {
        tem=net[i];
        while(-1 != tem)
        {
            if(1 == (1&tem))
            {
                tem=edge[tem].next;
                continue;
            }
            if(tem/2+1 > mm)
            {
                tem=edge[tem].next;
                continue;
            }
            if(1 == hash[i] && 0 == hash[edge[tem].v])
            {
                order[sum]=tem/2+1;
                sum++;
            }
            tem=edge[tem].next;
        }
    }
    printf("%d",sum);
    for(i=0;i<sum;i++)
    {
        printf(" %d",order[i]);
    }
    printf("\n");
}


 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值