ZOJ3229 Shoot the Bullet
有源汇的上下界网络流求最大流……(悄悄嘀咕一句,我也想给小姐姐拍照……)
题目大意:Aya要给一群小姐姐拍照。她在n天(n <= 365)天内会给m个小姐姐(m <= 1000)拍照,给第i个小姐姐拍照的总数不得少于给定的\(G_i\)。她每天只能给给定的几个小姐姐拍照,而且每天有一定的上下界。问在符合要求的情况下她最多能给所有小姐姐一共拍多少张照片。如果能满足要求,还要输出每天给哪些小姐姐分别拍了多少照片(与给定顺序一致)。
建图还是不难想到的。建立源汇点,原点向每天连一条边容量为0,每天向当天能拍摄的小姐姐脸边,容量为上界减下界,每个小姐姐向汇点连边,容量为INF-下界。之后先建立辅助源汇点跑一次可行流,如果没有可行流则不合法,否则在原图上因为可能还有残余网络,删除辅助源汇点,再在原图的源汇点上跑一次最大流,两次的和为答案。然后输出每天拍的照片的时候,因为链前是反着存图的,所以还要压个栈。
看一下代码。
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cmath>
#include<set>
#include<vector>
#include<map>
#include<queue>
#define rep(i,a,n) for(int i = a;i <= n;i++)
#define per(i,n,a) for(int i = n;i >= a;i--)
#define enter putchar('\n')
#define fr friend inline
#define y1 poj
#define mp make_pair
#define pr pair<int,int>
#define fi first
#define sc second
#define pb push_back
using namespace std;
typedef long long ll;
const int M = 40005;
const int N = 100005;
const int INF = 0x3f3f3f3f;
const double eps = 1e-7;
int read()
{
int ans = 0,op = 1;char ch = getchar();
while(ch < '0' || ch > '9') {if(ch == '-') op = -1;ch = getchar();}
while(ch >= '0' && ch <= '9') ans = ans * 10 + ch - '0',ch = getchar();
return ans * op;
}
struct edge
{
int next,to,from,v;
}e[N<<3];
int head[N],cur[N],deg[N],x,y,z,n,m,g,ecnt,S,T,S1,T1,c,d,tot;
int low[2005][2005],dep[N],sta[N],top;
queue <int> q;
void add(int x,int y,int z)
{
e[++ecnt].to = y;
e[ecnt].next = head[x];
e[ecnt].v = z;
head[x] = ecnt;
}
void clear()
{
memset(head,-1,sizeof(head)),ecnt = -1,tot = 0;
memset(deg,0,sizeof(deg));
memset(low,0,sizeof(low));
}
bool bfs(int s,int t)
{
while(!q.empty()) q.pop();
rep(i,0,t) cur[i] = head[i];
memset(dep,-1,sizeof(dep));
dep[s] = 0,q.push(s);
while(!q.empty())
{
int k = q.front();q.pop();
for(int i = head[k];~i;i = e[i].next)
{
if(e[i].v && dep[e[i].to] == -1)
dep[e[i].to] = dep[k] + 1,q.push(e[i].to);
}
}
return dep[t] != -1;
}
int dfs(int s,int t,int lim)
{
if(s == t || !lim) return lim;
int flow = 0;
for(int i = cur[s];~i;i = e[i].next)
{
cur[s] = i;
if(dep[e[i].to] != dep[s] + 1) continue;
int f = dfs(e[i].to,t,min(lim,e[i].v));
if(f)
{
e[i].v -= f,e[i^1].v += f;
flow += f,lim -= f;
if(!lim) break;
}
}
if(!flow) dep[s] = -1;
return flow;
}
int dinic(int s,int t)
{
int maxflow = 0;
while(bfs(s,t)) maxflow += dfs(s,t,INF);
return maxflow;
}
int main()
{
//freopen("f.in","r",stdin);
//freopen("f.out","w",stdout);
while(scanf("%d%d",&n,&m) != EOF)
{
T = n + m + 1,S1 = T + 1,T1 = S1 + 1;
clear();
rep(i,1,m) g = read(),add(i+n,T,INF-g),add(T,i+n,0),deg[i+n] += g,deg[T] -= g;
rep(i,1,n)
{
c = read(),d = read();
add(S,i,d),add(i,S,0);
rep(j,1,c)
{
x = read()+1,y = read(),z = read(),add(i,x+n,z-y),add(x+n,i,0);
deg[i] += y,deg[x+n] -= y,low[i][x] = y;
}
}
rep(i,S,T)
{
if(deg[i] > 0) add(i,T1,deg[i]),add(T1,i,0),tot += deg[i];
else add(S1,i,-deg[i]),add(i,S1,0);
}
add(T,S,INF),add(S,T,0);
int g = dinic(S1,T1);
//printf("%d %d\n",g,e[ecnt].v);
if(g != tot) {printf("-1\n");enter;continue;}
g = e[ecnt].v,e[ecnt].v = e[ecnt-1].v = 0;
printf("%d\n",g + dinic(S,T));
rep(i,1,n)
{
for(int j = head[i];~j;j = e[j].next)
{
if(e[j].to > n && e[j].to <= n + m) sta[++top] = e[j^1].v + low[i][e[j].to-n];
}
while(top) printf("%d\n",sta[top--]);
}
enter;
}
return 0;
}
当你意识到,每个上一秒都成为永恒。