题意:
一个屌丝给m个女神拍照,计划拍照n天,每一天屌丝给给定的C个女神拍照,每天拍照数不能超过D张,而且给每个女神i拍照有数量限制[Li,Ri],对于每个女神n天的拍照总和不能少于Gi,如果有解求屌丝最多能拍多少张照,并求每天给对应女神拍多少张照;否则输出-1。
分析:
增设一源点st,汇点sd,st到第i天连一条上界为Di下界为0的边,每个女神到汇点连一条下界为Gi上界为oo的边,对于每一天,当天到第i个女孩连一条[Li,Ri]的边。
建图模型:源点s,终点d。超级源点ss,超级终点dd。首先判断是否存在满足所有边上下界的可行流,方法可以转化成无源汇有上下界的可行流问题。怎么转换呢?
增设一条从d到s没有下界容量,上界容量为无穷的边,那么原图就变成了一个无源汇的循环流图。接下来的事情一样,超级源点ss连i(du[i]>0),i连超级汇点(du[i]<0),
对(ss,dd)进行一次最大流,当maxflow等于所有(du[]>0)之和时,有可行流,否则没有。
当有可行流时,再对(s,d)进行一次最大流,此时得到的maxflow则为题目的解。
为什么呢?因为第一次maxflow()只是求得所有满足下界的流量,而残留网络(s,d)路上还有许多自由流(没有和超级源点和超级汇点连接的边)没有流满,所有最终得到的maxflow=(第一次流满下界的流+第二次能流通的自由流)。
#include<cstdio>
#include<cstring>
#include<map>
#include<vector>
#include<cmath>
#include<cstdlib>
#include<stack>
#include<queue>
#include <iomanip>
#include<iostream>
#include<algorithm>
using namespace std ;
const int N=2000;
const int M=1000000;
const int inf=1<<30;
struct node
{
int u,v,c,next;
}edge[M];
int head[N],gap[N],pre[N],cur[N],dis[N];
int d[N],low[555][1111],flag[555][1111],top ;
int s,t;
void add(int u ,int v,int c)
{
edge[top].u=u;
edge[top].v=v;
edge[top].c=c;
edge[top].next=head[u];
head[u]=top++;
edge[top].u=v;
edge[top].v=u;
edge[top].c=0;
edge[top].next=head[v];
head[v]=top++;
}
int BFS()
{
memset(dis,-1,sizeof(dis));
queue<int>q ;
q.push(s);
dis[s]=0;
while(!q.empty())
{
int u = q.front();
q.pop();
for(int i = head[u] ; i!=-1 ; i=edge[i].next)
{
int v =edge[i].v ;
if(edge[i].c >0 && dis[v]==-1)
{
dis[v]=dis[u]+1;
q.push(v);
}
}
}
if(dis[t]==-1)
return 0;
return 1;
}
int DFS(int u ,int minx)
{
if(u==t) return minx ;
int tmp ;
for(int i = head[u];i!=-1 ; i=edge[i].next)
{
int v=edge[i].v;
if(edge[i].c >0 && dis[v]==dis[u]+1 && (tmp=DFS(v,min(minx,edge[i].c))))
{
edge[i].c -= tmp;
edge[i^1].c+=tmp;
return tmp ;
}
}
dis[u]=-1;
return 0;
}
int Dinic()
{
int ans= 0 , tmp;
while(BFS()) //找层次图 ,直到不能找到
{
while(1)
{
tmp = DFS(s,inf);
if(tmp==0) break;
ans += tmp ;
}
}
return ans ;
}
int main()
{
int n,m,x,C,T,u,l,h;
while(~scanf("%d%d",&n,&m))
{
top = 0 ;
memset(head,-1,sizeof(head));
memset(d,0,sizeof(d));
memset(low,0,sizeof(low));
memset(flag,0,sizeof(flag));
s=0,t=n+m+1;
for(int i = 1 ; i <= m ; i++)
{
scanf("%d",&x);
d[n+i] -= x;
add(n+i,t,inf-x);
d[t] += x;
}
for(int i = 1 ; i <= n ; i++)
{
scanf("%d%d",&C,&T);
add(s,i,T);
while(C--)
{
scanf("%d%d%d",&u,&l,&h);
u++;
add(i,n+u,h-l);
d[i] -= l ;
d[u+n] += l ;
low[i][u]=l;
flag[i][u]=top-2;
}
}
int ss = t+1 ,tt=t+2 , sum= 0 ;
for(int i = 1 ; i <= t ;i++)
{
if(d[i] > 0)
{
add(ss,i,d[i]);
sum += d[i] ;
}
else if(d[i] < 0)
add(i,tt,-d[i]) ;
}
add(t,s,inf);
s=ss;t=tt;
int maxflow = Dinic();
if(maxflow == sum)
{ s=0,t=n+m+1;
int ans = Dinic();
printf("%d\n",ans);
for(int i = 1 ; i <= n ; i++)
for(int j = 1 ; j <= m ; j++)
{
if(flag[i][j])
printf("%d\n",edge[flag[i][j]^1].c+low[i][j]);
}
}else
printf("-1\n");
puts("");
}
return 0;
}