/*
题目大意:某人n天给m个美女拍照
每个美女都有一个最低要求
每天有一个照片数量上限
先给出n m
每个美女的下限
n个{ 第i天拍照的美女数 这天的照片数量上限
依次是 美女编号 这天的下限 上限
}
有源汇 有上下界 最大流
先对 附加 源汇ss tt求依次最大流
若有可行流 再对s t求最大流
这是第二次写这个题,第一次写的挺不顺利
(可能是构图的时候出问题了,不是超时就是错,求最大流的方法就换了三种:sap递归,sap非递归,dinic
我都怀疑我的最大流模版是不是有漏洞,下面的递归sap就是最初用的,当时我还以为这个有问题,
其实,还真有一个问题,下面有,但是该了还是超时,今天看来,是构图的问题)
下面的 非递归sap跑了330ms 递归sap跑了270ms 看来我的模版速度还是不错的
*/
#include<stdio.h>
#include<string.h>
#define inf 0x7fffffff
struct edge//边
{
int u,v,f,next,b,c;//边的 前节点 后节点 可用流 下条边的编号 原来边上流的上下界
}e[400000];
int head[1400],in[1400],out[1400],n,m,s,t,ss,tt,yong,indexx[400000],ind,sum;
/*
head 链表头 in 某点的 流入下界和 - 流出下界和 out没用到
yong 指向下一个未用的边 indexx 存储某个美女某天的边的编号index在string.h里边有所以改成这个了 ind 表示下一个未用的 indexx
sum 流入tt的流量和 判断有无可行解用
*/
void ini()//初始化
{
memset(head,-1,sizeof(head));
yong=0;
memset(in,0,sizeof(in));
s=m+n,t=s+1,ss=t+1,tt=ss+1;
ind=0;
sum=0;
}
void adde(int from,int to,int xia,int shang)//加边
{//加边
e[yong].u=from,e[yong].v=to,e[yong].f=shang-xia,e[yong].b=xia,e[yong].c=shang;
e[yong].next=head[from],head[from]=yong++;
//同时加它的退边
e[yong].u=to,e[yong].v=from,e[yong].f=0,e[yong].b=xia,e[yong].c=shang;
e[yong].next=head[to],head[to]=yong++;
}
void build()//构造必要弧
//http://blog.csdn.net/qq172108805/article/details/7783010上有关于这个的简要说明
{
int i;
for(i=0;i<=t;++i)
{
if(in[i]>0)
adde(ss,i,0,in[i]);
else
{
adde(i,tt,0,-in[i]);
sum+=(-in[i]);
}
}
}
int sap(int s,int t)//非递归sap
{
int i,j,ff=0,v,cur[1400],d[1400],num[1400],low[1400],pre[1400];
memset(low,0,sizeof(low));
memset(d,0,sizeof(d));
memset(num,0,sizeof(num));
for(i=0;i<=t;++i)
cur[i]=head[i];
low[i=s]=inf;
num[s]=t+1;
while(d[s]<t+1)
{
for(j=cur[i];j!=-1;j=e[j].next)
if(e[j].f>0&&d[i]==d[v=e[j].v]+1)
break;
cur[i]=j;
if(j>=0)
{
pre[v]=j;
low[v]=e[j].f;
if(low[v]>low[i])
low[v]=low[i];
i=v;
if(i==t)
{
for(;i!=s;i=e[pre[i]].u)
{
e[pre[i]].f-=low[t];
e[pre[i]^1].f+=low[t];
}
ff+=low[t];
memset(low,0,sizeof(low));
low[s]=inf;
}
}else
{
if(--num[d[i]]==0)
break;
d[i]=t+1;
cur[i]=head[i];
for(j=head[i];j!=-1;j=e[j].next)
if(e[j].f>0&&d[i]>d[e[j].v]+1)
d[i]=d[e[j].v]+1;
num[d[i]]++;
if(i!=s)
i=e[pre[i]].u;
}
}
return ff;
}
int d[1400],num[1400];
int min(int a,int b){return a<b?a:b;}
int sap_gap(int u,int f,int s,int t)//递归sap
{
if(u==t)
return f;
int i,v,mind=t,last=f,cost;
for(i=head[u];i!=-1;i=e[i].next)
{
v=e[i].v;
int flow=e[i].f;
if(flow>0)//参考模版写的时候把flow写成了f
{
if(d[u]==d[v]+1)
{
cost=sap_gap(v,min(last,flow),s,t);
e[i].f-=cost;
e[i^1].f+=cost;
last-=cost;
if(d[s]>=t+1)
return f-last;
if(last==0)
break;
}
if(d[v]<mind)
mind=d[v];
}
}
if(last==f)
{
--num[d[u]];
if(num[d[u]]==0)
d[s]=t+1;
d[u]=mind+1;
++num[d[u]];
}
return f-last;
}
int max_f(int s,int t)//调用递归sap
{
int f=0;
memset(d,0,sizeof(d));
memset(num,0,sizeof(num));
for(num[s]=t+1;d[s]<t+1;)
f+=sap_gap(s,inf,s,t);
return f;
}
int main()
{
int i,a,c,b,ng,most,sun;
while(scanf("%d%d",&n,&m)!=EOF)
{
ini();
for(i=0;i<m;i++)
{
scanf("%d",&a);
adde(i,t,a,inf);
in[t]+=a;
in[i]-=a;
}
for(;i<m+n;++i)
{
scanf("%d%d",&ng,&most);
adde(s,i,0,most);
while(ng--)
{
scanf("%d%d%d",&a,&b,&c);
indexx[ind++]=yong;
adde(i,a,b,c);
in[a]+=b;
in[i]-=b;
}
}
adde(t,s,0,inf);
build();
//sun=sap(s,tt);//非递归sap
sun=max_f(ss,tt);//递归sap
if(sun!=sum)
{
printf("-1\n");
}else
{
//sap(s,t);//非递归sap
max_f(s,t);//递归sap
b=0;
for(i=0;i<ind;++i)
{
a=indexx[i];
b+=e[a].c-e[a].f;
}
printf("%d\n",b);
for(i=0;i<ind;++i)
{
a=indexx[i];
printf("%d\n",e[a].c-e[a].f);
}
}
printf("\n");
}
return 0;
}
zoj 3229 Shoot the Bullet--有源汇 有上下界 最大流 递归和非递归sap
最新推荐文章于 2018-10-04 20:11:57 发布