/** zoj提交评判不了,所以不知道代码正不正确。思路是应该没问题的。如果有不对的地方,请多指教。 题目:Shoot the Bullet ZOJ - 3229 链接:https://vjudge.net/problem/20756 题意: 高富帅给m个女神拍照,拍照n天,第i天给ci个女神拍照,给出了具体ci个女神的编号,以及在第i天给ci个女神分别给出拍照数量限制[l,r]。 第i天最多拍照Di次。拍照n天后,第i个女神总共最少拍照Gi次。求高富帅最多拍照次数。 思路: 建立源点s,t. s指向所有的天数,下界为0,上界为Di。所有的女神指向t,下界为Gi,上界INF。天数指向女神,下界为l,上界为r。 将有源汇有上下界变成无源汇有上界,求可行流。 t指向s,下界为0,上界为INF。增加超级源汇点S,T。 对于每个点i。in[i]表示入度的边的下界和,out[i]表示出度的边的下界和,为了进出该节点流量相等。 如果in[i]>out[i],那么S连一条到i的下界为0,上界为in[i]-out[i]的边。 如果in[i]<out[i],那么i连一条到T的下界为0,上界为out[i]-in[i]的边。 S到T跑最大流。如果flow== 所有in[i]-out[i]的和 (当in[i]>out[i]) 即:附加边都是满载。 那么有可行流。 然后在求一次s到t的最大流即是最终结果。不需要删除t到s的那条上界INF的边,也不用删除S,T.因为跑s到t的最大流的时候,t->s的流量会增广s->t回流,这里的回流值便是所有的下界和。 所以s到t的最大流就是最终的结果,已经包括了所有下界的值。 至于S,T不影响s到t的最大流,已经满载。根据dinic,只走残留网络,所以无法到达T。到达S的路径无法到达t.所以不受影响。 具体某一天某女神的拍照数量则要加上相应的下界值。 */ #include<iostream> #include<cstring> #include<vector> #include<map> #include<cstdio> #include<algorithm> #include<queue> using namespace std; const int INF = 0x3f3f3f3f; typedef long long LL; const int N = 1440;///n+m=1365 int in[N]; int out[N]; struct Edge{ int from, to, cap, flow; Edge(int u,int v,int c,int f):from(u),to(v),cap(c),flow(f){} }; struct Dinic{ int n, m, s, t; vector<Edge> edges; vector<int> G[N]; bool vis[N]; int d[N]; int cur[N]; void init(int n) { this->n = n; for(int i = 0; i <= n; i++) G[i].clear(); edges.clear(); } void AddEdge(int from,int to,int cap) { edges.push_back(Edge(from,to,cap,0)); edges.push_back(Edge(to,from,0,0)); m = edges.size(); G[from].push_back(m-2); G[to].push_back(m-1); } bool BFS() { memset(vis, 0, sizeof vis); queue<int> Q; Q.push(s); d[s] = 0; vis[s] = 1; while(!Q.empty()) { int x = Q.front(); Q.pop(); for(int i = 0; i < G[x].size(); i++) { Edge &e = edges[G[x][i]]; if(!vis[e.to]&&e.cap>e.flow) { vis[e.to] = 1; d[e.to] = d[x]+1; Q.push(e.to); } } } return vis[t]; } int DFS(int x,int a) { if(x==t||a==0) return a; int flow = 0, f; for(int &i = cur[x]; i < G[x].size(); i++) { Edge& e = edges[G[x][i]]; if(d[x]+1==d[e.to]&&(f=DFS(e.to,min(a,e.cap-e.flow)))>0) { e.flow += f; edges[G[x][i]^1].flow -= f; flow += f; a -= f; if(a==0) break; } } return flow; } int Maxflow(int s,int t) { this->s = s, this->t = t; int flow = 0; while(BFS()) { memset(cur, 0, sizeof cur); flow += DFS(s,INF); } return flow; } }; vector<int> ans; vector<int> dw; int main() { int n, m; while(scanf("%d%d",&n,&m)==2) { int s = 0, t = n+m+1; Dinic dinic; dinic.init(t+2); memset(in, 0, sizeof in); memset(out, 0, sizeof out); ans.clear(); dw.clear(); int G; for(int i = 1; i <= m; i++){ scanf("%d",&G); dinic.AddEdge(i+n,t,INF); in[t]+=G; out[i+n]+=G; } int C, D, T, L, R; for(int i = 1; i <= n; i++){ scanf("%d%d",&C,&D); dinic.AddEdge(s,i,D); for(int j = 1; j <= C; j++){ scanf("%d%d%d",&T,&L,&R); T++; dinic.AddEdge(i,T+n,R-L);///T+n( ⊙ o ⊙ )啊! ans.push_back(dinic.edges.size()-2); dw.push_back(L); out[i]+=L; in[T+n]+=L; } } dinic.AddEdge(t,s,INF); int ss = t+1, tt = t+2; int sum = 0; for(int i = 1; i <= t; i++){ if(in[i]>out[i]){ sum += in[i]-out[i]; dinic.AddEdge(ss,i,in[i]-out[i]); } if(in[i]<out[i]){ dinic.AddEdge(i,tt,out[i]-in[i]); } } int flow = dinic.Maxflow(ss,tt); //cout<<"sum = "<<sum<<endl; //cout<<"flow = "<<flow<<endl; if(flow==sum){ printf("%d ",dinic.Maxflow(s,t));///这个就是最大流,但是下面的具体flow需要再加上 下界。 for(int i = 0; i < ans.size(); i++){ printf("%d ",dinic.edges[ans[i]].flow+dw[i]); } }else { printf("-1 "); } printf(" "); } return 0; }