题意:
一个屌丝给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)之和时,有可行流,否则没有。
当有可行流时,删除超级源点ss和超级终点dd,再对(s,d)进行一次最大流,此时得到的maxflow则为题目的解。
为什么呢?因为第一次maxflow()只是求得所有满足下界的流量,而残留网络(s,d)路上还有许多*流(没有和超级源点和超级汇点连接的边)没有流满,所有最终得到的maxflow=(第一次流满下界的流+第二次能流通的*流)。
// File Name: 3229.cpp
// Author: Zlbing
// Created Time: 2013/6/30 20:44:46 #include<iostream>
#include<string>
#include<algorithm>
#include<cstdlib>
#include<cstdio>
#include<set>
#include<map>
#include<vector>
#include<cstring>
#include<stack>
#include<cmath>
#include<queue>
using namespace std;
#define CL(x,v); memset(x,v,sizeof(x));
#define INF 0x3f3f3f3f
#define LL long long
#define REP(i,r,n) for(int i=r;i<=n;i++)
#define RREP(i,n,r) for(int i=n;i>=r;i--)
const int MAXN=;
struct Edge{
int from,to,cap,flow;
};
bool cmp(const Edge& a,const Edge& b){
return a.from < b.from || (a.from == b.from && a.to < b.to);
}
struct Dinic{
int n,m,s,t;
vector<Edge> edges;
vector<int> G[MAXN];
bool vis[MAXN];
int d[MAXN];
int cur[MAXN];
void init(int n){
this->n=n;
for(int i=;i<=n;i++)G[i].clear();
edges.clear();
}
void AddEdge(int from,int to,int cap){
edges.push_back((Edge){from,to,cap,});
edges.push_back((Edge){to,from,,});//当是无向图时,反向边容量也是cap,有向边时,反向边容量是0
m=edges.size();
G[from].push_back(m-);
G[to].push_back(m-);
}
bool BFS(){
CL(vis,);
queue<int> Q;
Q.push(s);
d[s]=;
vis[s]=;
while(!Q.empty()){
int x=Q.front();
Q.pop();
for(int i=;i<G[x].size();i++){
Edge& e=edges[G[x][i]];
if(!vis[e.to]&&e.cap>e.flow){
vis[e.to]=;
d[e.to]=d[x]+;
Q.push(e.to);
}
}
}
return vis[t];
}
int DFS(int x,int a){
if(x==t||a==)return a;
int flow=,f;
for(int& i=cur[x];i<G[x].size();i++){
Edge& e=edges[G[x][i]];
if(d[x]+==d[e.to]&&(f=DFS(e.to,min(a,e.cap-e.flow)))>){
e.flow+=f;
edges[G[x][i]^].flow-=f;
flow+=f;
a-=f;
if(a==)break;
}
}
return flow;
}
//当所求流量大于need时就退出,降低时间
int Maxflow(int s,int t,int need){
this->s=s;this->t=t;
int flow=;
while(BFS()){
CL(cur,);
flow+=DFS(s,INF);
if(flow>need)return flow;
}
return flow;
}
//最小割割边
vector<int> Mincut(){
BFS();
vector<int> ans;
for(int i=;i<edges.size();i++){
Edge& e=edges[i];
if(vis[e.from]&&!vis[e.to]&&e.cap>)ans.push_back(i);
}
return ans;
}
void Reduce(){
for(int i = ; i < edges.size(); i++) edges[i].cap -= edges[i].flow;
}
void ClearFlow(){
for(int i = ; i < edges.size(); i++) edges[i].flow = ;
}
}; int n,m;
Dinic solver;
int du[MAXN];
int dn[MAXN][MAXN];
int id[MAXN][MAXN];
int main()
{
while(~scanf("%d%d",&n,&m))
{
int s=,t=n+m+;
int ss=n+m+,tt=n+m+;
int a,b,c;
CL(du,);
CL(dn,);
CL(id,);
solver.init(n+m+);
REP(i,,m)
{
scanf("%d",&a);
solver.AddEdge(n+i,t,INF-a);
du[n+i]-=a;
du[t]+=a;
}
int C,D;
REP(i,,n)
{
scanf("%d%d",&C,&D);
solver.AddEdge(s,i,D);
REP(j,,C)
{
scanf("%d%d%d",&a,&b,&c);
solver.AddEdge(i,a+n+,c-b);
du[i]-=b;
du[a+n+]+=b;
dn[i][a]=b;
id[i][a]=solver.edges.size()-;
}
}
solver.AddEdge(t,s,INF);
int sum=;
REP(i,,t)
{
if(du[i]<)
{
solver.AddEdge(i,tt,-du[i]);
}
else if(du[i]>)
{
solver.AddEdge(ss,i,du[i]);
sum+=du[i];
}
}
int maxflow=solver.Maxflow(ss,tt,INF);
if(maxflow==sum)
{
int ans=solver.Maxflow(s,t,INF);
printf("%d\n",ans);
for(int i=;i<=n;i++)
{
for(int j=;j<m;j++)
if(id[i][j])
printf("%d\n",solver.edges[id[i][j]].flow+dn[i][j]);
}
}
else printf("-1\n");
printf("\n");
}
return ;
}
zoj3229 Shoot the Bullet(有源汇有上下界的最大流)的更多相关文章
-
ZOJ3229 Shoot the Bullet(有源汇的上下界最大流)
#pragma warning(disable:4996) #include <iostream> #include <cstring> #include <string ...
-
Shoot the Bullet(有源汇带上下界最大流)
有源汇带上下界最大流 在原图基础上连一条汇点到源点流量为inf的边,将有源汇网络流转化为无源汇网络流用相同方法判断是否满流,如果满流再跑一边源点到汇点的最大流就是答案 例题:Shoot the Bul ...
-
Shoot the Bullet ZOJ - 3229 有源汇有上下界的最大流
/** zoj提交评判不了,所以不知道代码正不正确.思路是应该没问题的.如果有不对的地方,请多指教. 题目:Shoot the Bullet ZOJ - 3229 链接:https://vjudge. ...
-
zoj3229 Shoot the Bullet (有源汇最大流)
题目大意:文文要给幻想乡的女♂孩子们拍照,一共n天,m个女♂孩子,每天文文至多拍D[i]张照片,每个女♂孩子总共要被文文至少拍G[i]次.在第i天,文文可以拍c[i]个女♂孩子,c[i]个女♂孩子中每 ...
-
zoj 3229 有源汇有上下界的最大流模板题
/*坑啊,pe的程序在zoj上原来是wa. 题目大意:一个屌丝给m个女神拍照.计划拍照n天,每一天屌丝最多个C个女神拍照,每天拍照数不能超过D张,并且给每一个女神i拍照有数量限制[Li,Ri], 对于 ...
-
BZOJ2055 80人环游世界 网络流 费用流 有源汇有上下界的费用流
https://darkbzoj.cf/problem/2055 https://blog.csdn.net/Clove_unique/article/details/54864211 ←对有上下界费 ...
-
sgu 176 有源汇有上下界的最小流模板题
/*参考博文:http://hi.baidu.com/dragon_eric123/item/82e259200ece744046996282 有上下界的有源最小流 */ #include<st ...
-
ZOJ 3229 Shoot the Bullet(有源汇上下界最大流)
题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=3442 题目大意: 一个屌丝给m个女神拍照,计划拍照n天,每一天屌丝给 ...
-
【模板】有源汇有上下界最大流(网络流)/ZOJ3229
先导知识 无源汇有上下界可行流 题目链接 https://vjudge.net/problem/ZOJ-3229 https://www.luogu.com.cn/problem/P5192 (有改动 ...
随机推荐
-
用U盘制作启动盘后空间变小的恢复方法,清除U盘启动盘空间
先把u盘插好,运行cmd, 输入diskpart,回车, (输入list disk,回车,能看到磁盘大致情况,u盘一般是磁盘1) 再输入select disk 1,回车, 再输入clean,回车, 关 ...
-
去掉mysql数据库字段中的个别字符
update 表名 set 列名 = REPLACE (mcategory,"要去掉的字符","") where 列名 like "%要去掉的字符% ...
-
static inline
今天看到了这样一段代码, static inline BOOL IsEmpty(id thing) { return thing == nil || [thing isEqual:[NSNull nu ...
-
select框的text与value值的获取(实用版)
function def(){ var key = document.getElementById ('selectarea'); //select list var value = docum ...
-
PLS-00103: 出现符号 ...
Oracle存储过程: create or replace procedure update_people(in_name ), in_status in nvarchar2) as begin up ...
-
HTTP笔记:URI与URL
URI与URL 简单理解是这样的:理解URI和URL的区别,我们引入URN这个概念.URI = Universal Resource Identifier 统一资源标志符URL = Universal ...
-
Unity3D 3D横版跑酷 跳跃
Unity3d 跑酷动画的控制 首先给个图吧, 我们跑酷里面需要动画的,今天说一下动画的知识! 1.导入骨骼动画模型文件之后,如果使用之前版本的unity的播放动画的方式,需要设置AnimationT ...
-
[jquery] 图片热区随图片大小*缩放
在图片上直接画出带超级链接热区元素map和area相信大家并不陌生,Dreamweaver等网页制作软件都有直接在图片上绘制带超级链接的热区工具,但是直接绘制的热区是不能随着图片自适应放大和缩小的,现 ...
-
WINFORM数据库操作,有点像安装里面的SQLITE
程序设计要求 设计一个用户管理系统,对系统中的用户进行管理.假定,用户表中有下列字段:用户名,密码,电话和 email 等信息.要求,1)利用 SQL server 首先创建用户数据表:2)实现对用户 ...
-
vim基本命令(转载自网络)
来源于<Unix初级教程(第四版)>. 命令模式切换到文本输入模式: 键 功能 i 在光标左侧输入文本 I 在当前行的行首输入文本 a 在光标右侧输入文本 A 在当前行的行尾输入文本 o ...