ZOJ3496:Assignment——题解
http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3496
题目大意:A公司从S到T运货,每条路都有一个运货上限,而B公司则有p点费用点可以分配到个个路上,设分配到一条路上的费用点为x,该路走了y个货物,则需收费x*y,在以运货最大为要求下,B公司想要最大化收费,A公司则需要求出费用最大时的最小值(最小化费用)。
但是还没完,你还需要求出同条件下B公司想要最小化收费,A公司费用最小时的最大值(最大化费用)。
————————————————————————————
一道好题,顺便把我前面博客的bug找了出来。
首先需要想到,做到费用最大时,我们大可以把p点都加在流量最大的边上,这样一定是费用最大的(贪心策略)。
并且看到最大值最小,我们立刻想到了二分答案。
那么我们就可以二分所放p点的流量求解。
那么我们将所有边的容量都更新为min(容量,二分答案)重新跑一遍最大流,并且和之前的最大流相比,如果变小了的话就说明答案一定是小的,需要变大,否则答案就过大,需要变小。
此时我们已经做完了第一问,现在思考第二问。
我们用同样的思路二分,将所有路的容量增加一个我们二分答案为下界跑上下界网络流最大流,与原最大流比较即可,更新的方式和上面正好相反。
PS:一组数据如下:
1
5 11 2 1 2
3 4 12
4 1 11
0 1 8
2 3 11
4 0 12
3 1 9
2 4 11
4 3 8
0 3 6
2 0 8
2 1 11
ans:22 12
这组数据特别之处在于它有一条从u到v的边,同时还有从v到u的边,一旦有这种情况,只要在上下界网络流中处理不好就会出错。
显然我们只能删除超级源汇点(甚至你可以不删除,也不会对答案有什么影响),而不能将其他的边删除,否则就会造成残余网络中的流量无法留到汇点从而WA掉。
#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=;
const int M=;
const int INF=0x3f3f3f3f;
inline int read(){
int X=,w=;char ch=;
while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
while(isdigit(ch))X=(X<<)+(X<<)+(ch^),ch=getchar();
return w?-X:X;
}
struct node{
int nxt,to,w;
}edge[M<<];
struct line{
int u,v,w;
}e[M];
int head[N],du[N],cnt=-,ans,maxw;
int S,T,n,m,st,ed;
ll p;
inline void add(int u,int v,int w){
cnt++;
edge[cnt].to=v;
edge[cnt].w=w;
edge[cnt].nxt=head[u];
head[u]=cnt;
return;
}
int lev[N],cur[N],dui[N];
bool bfs(int k){
int r=;
for(int i=;i<=k;i++){
lev[i]=-;
cur[i]=head[i];
}
dui[]=S,lev[S]=;
int u,v;
for(int l=;l<=r;l++){
u=dui[l];
for(int e=head[u];e!=-;e=edge[e].nxt){
v=edge[e].to;
if(edge[e].w>&&lev[v]==-){
lev[v]=lev[u]+;
r++;
dui[r]=v;
if(v==T)return ;
}
}
}
return ;
}
int dinic(int u,int flow,int k){
if(u==k)return flow;
int res=,delta;
for(int &e=cur[u];e!=-;e=edge[e].nxt){
int v=edge[e].to;
if(edge[e].w>&&lev[u]<lev[v]){
delta=dinic(v,min(edge[e].w,flow-res),k);
if(delta>){
edge[e].w-=delta;
edge[e^].w+=delta;
res+=delta;
if(res==flow)break;
}
}
}
if(res!=flow)lev[u]=-;
return res;
}
//////////
bool check1(int k){
memset(head,-,sizeof(head));
cnt=-;
for(int i=;i<=m;i++){
add(e[i].u,e[i].v,min(k,e[i].w));
add(e[i].v,e[i].u,);
}
int awe=;S=st,T=ed;
while(bfs(n))awe+=dinic(S,INF,T);
return awe==ans;
}
ll solve1(){
int l=,r=maxw;
ll awe=;
while(l<=r){
int mid=(l+r)>>;
if(check1(mid)){
awe=mid;
r=mid-;
}else l=mid+;
}
return awe*p;
}
//////////////
bool check2(int k){
memset(head,-,sizeof(head));
memset(du,,sizeof(du));
cnt=-;
for(int i=;i<=m;i++){
if(e[i].w<k)return ;
add(e[i].u,e[i].v,e[i].w-k);
add(e[i].v,e[i].u,);
du[e[i].u]-=k;
du[e[i].v]+=k;
}
add(ed,st,INF);add(st,ed,);
S=n+;T=S+;
int awe=,full=;
for(int i=;i<=n;i++){
if(du[i]>){
add(S,i,du[i]);
add(i,S,);
full+=du[i];
}
else if(du[i]<){
add(i,T,-du[i]);
add(T,i,);
}
}
while(bfs(T))awe+=dinic(S,INF,T);
if(full!=awe)return ;
head[S]=head[T]=-;
S=st;T=ed;
awe=;
while(bfs(n))awe+=dinic(S,INF,T);
return awe==ans;
}
ll solve2(){
int l=,r=maxw;
ll awe=;
while(l<=r){
int mid=(l+r)>>;
if(check2(mid)){
awe=mid;
l=mid+;
}else r=mid-;
}
return awe*p;
}
int main(){
int t=read();
while(t--){
n=read(),m=read(),st=read()+,ed=read()+,p=read();
memset(head,-,sizeof(head));
maxw=;cnt=-;
for(int i=;i<=m;i++){
e[i].u=read()+,e[i].v=read()+,e[i].w=read();
add(e[i].u,e[i].v,e[i].w);
add(e[i].v,e[i].u,);
maxw=max(maxw,e[i].w);
}
S=st,T=ed;ans=;
while(bfs(n))ans+=dinic(S,INF,T);
printf("%lld %lld\n",solve1(),solve2());
}
return ;
}
ZOJ3496:Assignment——题解的更多相关文章
- ZOJ3496 Assignment
传送门 这题也是真恶心-- 题目大意是俩公司要运货,每条路有容量上限.然后B公司手里有p个--(技能点?)如果在一条路上放了x个技能点,这条路经过了y个货物,那么B公司就会收x*y的钱.现在要求的是, ...
- Lintcode208 Assignment Operator Overloading (C++ Only) solution 题解
[题目描述] Implement an assignment operator overloading method. Make sure that: The new data can be copi ...
- hdu4781 Assignment For Princess(构造)
题目链接:hdu4781 Assignment For Princess 题意:n个点m条边,每条有向边的权值分别是1,2,3…m,一个点能到达任意一个点,没有重边和自环,没有任何两条边的权值相同,任 ...
- 2017 google Round C APAC Test 题解
题解参考网上的答案,以及我自己的想法. 主要参考网站:http://codeforces.com/blog/entry/47181,http://codeforces.com/blog/entry/4 ...
- 2015 Multi-University Training Contest 1 题解&&总结
---------- HDU 5288 OO’s Sequence 题意 给定一个数列(长度<$10^5$),求有多少区间[l,r],且区间内有多少数,满足区间内其它数不是他的约数. 数的范围$ ...
- HDU 2853 Assignment(KM最大匹配好题)
HDU 2853 Assignment 题目链接 题意:如今有N个部队和M个任务(M>=N),每一个部队完毕每一个任务有一点的效率,效率越高越好.可是部队已经安排了一定的计划,这时须要我们尽量用 ...
- 题解——CodeForces 438D The Child and Sequence
题面 D. The Child and Sequence time limit per test 4 seconds memory limit per test 256 megabytes input ...
- HDU - 5289 Assignment (RMQ+二分)(单调队列)
题目链接: Assignment 题意: 给出一个数列,问其中存在多少连续子序列,使得子序列的最大值-最小值<k. 题解: RMQ先处理出每个区间的最大值和最小值(复杂度为:n×logn),相 ...
- HDU 5289 Assignment rmq
Assignment 题目连接: http://acm.hdu.edu.cn/showproblem.php?pid=5289 Description Tom owns a company and h ...
随机推荐
- xencenter迁移云主机方法
问题:POOL中计算节点内存不足. 解决方法:1.为计算节点添加内存(费用高)2.将部分资源迁移到其它POOL中. 方法: 1.选择要迁移的虚拟机 2.选择保存路径 这里可以看到可以批量导出: 注意: ...
- Qt 报错onecoreuap\inetcore\urlmon\zones\zoneidentifier.cxx(359)\urlmon.dll!00007FF9D9FA5B50:
具体报错内容 onecoreuap\inetcore\urlmon\zones\zoneidentifier.cxx(359)\urlmon.dll!00007FF9D9FA5B50: (caller ...
- python切片技巧
写一个程序,打印数字1到100,3的倍数打印“Fizz”来替换这个数,5的倍数打印“Buzz”,对于既是3的倍数又是5的倍数的数字打印“FizzBuzz” for x in range(101): p ...
- Java VisualVM使用
Java VisualVM Java VisualVM官网 Java VisualVM介绍 Java VisualVM is a tool that provides a visual interfa ...
- 基于AdaBoost算法——世纪晟结合Haar-like特征训练人脸检测识别
AdaBoost 算法是一种快速人脸检测算法,它将根据弱学习的反馈,适应性地调整假设的错误率,使在效率不降低的情况下,检测正确率得到了很大的提高. 系统在技术上的三个贡献: 1.用简单的Haa ...
- GRU-CTC中文语音识别
目录 基于keras的中文语音识别 音频文件特征提取 文本数据处理 数据格式处理 构建模型 模型训练及解码 aishell数据转化 该项目github地址 基于keras的中文语音识别 该项目实现了G ...
- 《剑指Offer》题二十一~题三十
二十一.调整数组顺序使奇数位于偶数前面 题目:输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有奇数位于数组的前半部分,所有偶数位于数组的后半部分. 测试用例: 功能测试:输入数组中的奇 ...
- Android之Bluetooth编程
Android Bluetopth 编程大牛文章 http://my.oschina.net/u/994235/blog?catalog=313604 ViewGroup 相关资料 : http:// ...
- 福大软工1816:Alpha(10/10)
Alpha 冲刺 (10/10) 队名:第三视角 组长博客链接 本次作业链接 团队部分 团队燃尽图 工作情况汇报 张扬(组长) 过去两天完成了哪些任务: 文字/口头描述: 1.和愈明.韫月一起对接 2 ...
- iOS- <项目笔记> UIApplication常见属性与方法总结
UIApplication 1.简介 1> 整个应用程序的象征,一个应用程序就一个UIApplication对象,使用了单例设计模式 2> 通过[UIApplication sharedA ...