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;
}