dinic算法的改进

dinic算法的改进


保存邻接表是使用的是head数组,现在另设一个head2数组,存储的是每个节点x从head2[x]开始的边才会有增广路,这样减少了无用边的循环。并且head2数组只在全局初始化一次,即如果没有增广,该值只会逐渐减小直到0。
在HDU3572中使用该优化可使时间从998ms优化值156ms

附上代码

/*注释的地方是与平常dinic不同的地方,注意即可
*/
#include<cstdio>
#include<iostream>
#include<queue>
#include<cstring>

using namespace std;

struct edge
{
    int y,l,next;
};

edge v[1000*1000+50];
int tot;
int head[1050];
int head2[1050];//***
int d[1050];
int st,ed;
int n,m;
int p[550];
int s[550];
int e[550];
int sump;

void add(int x,int y,int l)
{
    tot++;
    v[tot].y=y; v[tot].l=l;
    v[tot].next=head[x]; head[x]=tot;
}

bool bfs()
{
    for (int i=1;i<=ed;i++)
    {
        d[i]=0;
    }
    queue<int> q;
    q.push(st);
    d[st]=1;
    int now=0;
    head2[st]=head[st];//***
    while (!q.empty())
    {
        now=q.front();
        q.pop();
        for (int i=head[now];i;i=v[i].next)
        {
            if (v[i].l>0 && !d[v[i].y])
            {
                d[v[i].y]=d[now]+1;
                head2[v[i].y]=head[v[i].y];//***
                q.push(v[i].y);
            }
        }
    }
    return d[ed];
}

int dinic(int x,int flow)
{
    if (x==ed) return flow;
    int temp=0;
    for (int i=head2[x];i;i=v[i].next)//***
    {
        if (d[v[i].y]==d[x]+1 && v[i].l>0)
        {
            int k=dinic(v[i].y,min(flow-temp,v[i].l));
            if (k)
            {
                temp+=k;
                v[i].l-=k;
                v[i^1].l+=k;
            }
        }
        head2[x]=i;//***
        if (temp==flow) return flow;
    }
    return temp;
}

int T;

int main()
{
    scanf("%d",&T);
    for (int tt=1;tt<=T;tt++)
    {
        scanf("%d%d",&n,&m);
        int l=1000;
        int r=0;
        sump=0;
        for (int i=1;i<=n;i++)
        {
            scanf("%d%d%d",&p[i],&s[i],&e[i]);
            l=min(l,s[i]);
            r=max(e[i],r);
            sump+=p[i];
        }
        tot=1;
        memset(head,0,sizeof(head));
        memset(head2,0,sizeof(head2));
        st=n+r-l+2;
        ed=n+r-l+3;
        for (int i=1;i<=n;i++)
        {
            add(st,i,p[i]);
            add(i,st,0);
            for (int j=s[i];j<=e[i];j++)
            {
                add(i,n+j-l+1,1);
                add(n+j-l+1,i,0);
            }
        }
        for (int i=l;i<=r;i++)
        {
            add(n+i-l+1,ed,m);
            add(ed,n+i-l+1,0);
        }

        int maxflow=0;
        int now=0;
        while (bfs())
        {
            maxflow+=dinic(st,0x3f3f3f3f);
        }

        printf("Case %d: ",tt);
        if (maxflow==sump)
        {
            printf("Yes\n");
        }
        else
        {
            printf("No\n");
        }
        printf("\n");
    }

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值