hdu 3987 Harry Potter and the Forbidden Forest 求割边最少的最小割

题意:

    求最小割,但因为最小割是不唯一的,题目要求得到最小割的条件下,使得割边最少,输出最少割边数

思路:

    有两种做法,但本质是一样的

  第一种:
    建边的时候每条边权 w = w * (E + 1) + 1;
    这样得到最大流 maxflow / (E + 1) ,最少割边数 maxflow % (E + 1)

    道理很简单,如果原先两类割边都是最小割,那么求出的最大流相等
    但边权变换后只有边数小的才是最小割了

    乘(E+1)是为了保证边数叠加后依然是余数,不至于影响求最小割的结果

  第二种:

    建图,得到最大流后,图中边若满流,说明该边是最小割上的边

    再建图,原则:满流的边改为容量为 1 的边,未满流的边改为容量 INF 的边,然后最大流即答案

 

由于题目需要乘上最大的边数  而题目的最大边数有100000 所以数会很大 需要用64.在错了无限多次后终于搞对了。记得是他的花费要超int

还有就是记得用c++编译不用g++不然inf会超long int

 先给出方法1的:耗时间78ms

#include<iostream> 
#include<cstdio> 
#include<memory.h> 
#include<cmath> 
using namespace std;   
#define MAXN 5010 
#define MAXE 1000100 
#define INF 100000000000000000   
int ne,nv,tmp,s,t,index;  
struct Edge{ 
    int next,pair,v; 
    __int64 cap,fLow; 
}edge[MAXE]; 
int net[MAXN]; 
__int64 ISAP() 
{ 
    int numb[MAXN],dist[MAXN],curedge[MAXN],pre[MAXN]; 
    __int64 cur_fLow,max_fLow;
	int u,tmp,neck,i; 
    memset(dist,0,sizeof(dist)); 
    memset(numb,0,sizeof(numb)); 
    memset(pre,-1,sizeof(pre)); 
    for(i = 1 ; i <= nv ; ++i) 
        curedge[i] = net[i]; 
    numb[nv] = nv; 
    max_fLow = 0; 
    u = s; 
    while(dist[s] < nv) 
    { 
        if(u == t) 
        { 
            cur_fLow = INF+1; 
            for(i = s; i != t;i = edge[curedge[i]].v)  
            {   
                if(cur_fLow > edge[curedge[i]].cap) 
                { 
                    neck = i; 
                    cur_fLow = edge[curedge[i]].cap; 
                } 
            } 
            for(i = s; i != t; i = edge[curedge[i]].v) 
            { 
                tmp = curedge[i]; 
                edge[tmp].cap -= cur_fLow; 
                edge[tmp].fLow += cur_fLow; 
                tmp = edge[tmp].pair; 
                edge[tmp].cap += cur_fLow; 
                edge[tmp].fLow -= cur_fLow; 
            } 
            max_fLow += cur_fLow; 
            u = neck; 
        } 
       for(i = curedge[u]; i != -1; i = edge[i].next) 
            if(edge[i].cap > 0 && dist[u] == dist[edge[i].v]+1) 
                break; 
        if(i != -1) 
        { 
            curedge[u] = i; 
            pre[edge[i].v] = u; 
            u = edge[i].v; 
        }else{ 
            if(0 == --numb[dist[u]]) break; 
            curedge[u] = net[u]; 
            for(tmp = nv,i = net[u]; i != -1; i = edge[i].next) 
                if(edge[i].cap > 0) 
                    tmp = tmp<dist[edge[i].v]?tmp:dist[edge[i].v]; 
            dist[u] = tmp + 1; 
            ++numb[dist[u]]; 
            if(u != s) u = pre[u]; 
        } 
    }      
    return max_fLow; 
}
void addedge(int u,int v,__int64 f)
{
    edge[index].next = net[u]; 
    edge[index].v = v; 
    edge[index].cap = f; 
    edge[index].fLow = 0; 
    edge[index].pair = index+1; 
    net[u] = index++; 
    edge[index].next = net[v]; 
    edge[index].v = u; 
    edge[index].cap = 0; 
    edge[index].fLow = 0; 
    edge[index].pair = index-1; 
    net[v] = index++;
    
} 
int main() { 
    int i,j,np,nc,m,n; 
    int a,b,d,k,vaL;
    int te;
    int cases=1;
    scanf("%d",&te); 
    while(te--) 
    { 
        scanf("%d%d",&n,&m);
        nv=n;
        index=1;
        if(n==0 && m==0) return 0;
        s = 1; 
        t = n; 
        memset(net,-1,sizeof(net));        
        
        for(i=1;i<=m;i++) 
        { 
            int u,v,d;
            __int64 c;
            scanf("%d%d%I64d%d",&u,&v,&c,&d);
            u++,v++;
            addedge(u,v,c*100001+1); 
            if(d)
            addedge(v,u,c*100001+1);
         }         
        __int64 ans=ISAP();
        printf("Case %d: %I64d\n", cases++, ans % 100001);

    } 
    return 0; 
}


 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值