bzoj2007 NOI2010 网络流转对偶图
2007: [Noi2010]海拔
Time Limit: 20 Sec Memory Limit: 552 MB
Submit: 2775 Solved: 1331
[Submit][Status][Discuss]
Description
YT市是一个规划良好的城市,城市被东西向和南北向的主干道划分为n×n个区域。简单起见,可以将YT市看作一个
正方形,每一个区域也可看作一个正方形。从而,YT城市中包括(n+1)×(n+1)个交叉路口和2n×(n+1)条双向道路
(简称道路),每条双向道路连接主干道上两个相邻的交叉路口。下图为一张YT市的地图(n = 2),城市被划分为2
×2个区域,包括3×3个交叉路口和12条双向道路。 小Z作为该市的市长,他根据统计信息得到了每天上班高峰期
间YT市每条道路两个方向的人流量,即在高峰期间沿着该方向通过这条道路的人数。每一个交叉路口都有不同的海
拔高度值,YT市市民认为爬坡是一件非常累的事情,每向上爬h的高度,就需要消耗h的体力。如果是下坡的话,则
不需要耗费体力。因此如果一段道路的终点海拔减去起点海拔的值为h(注意h可能是负数),那么一个人经过这段路
所消耗的体力是max{0, h}(这里max{a, b}表示取a, b两个值中的较大值)。 小Z还测量得到这个城市西北角的交
叉路口海拔为0,东南角的交叉路口海拔为1(如上图所示),但其它交叉路口的海拔高度都无法得知。小Z想知道在
最理想的情况下(即你可以任意假设其他路口的海拔高度),每天上班高峰期间所有人爬坡所消耗的总体力和的最
小值。
Input
第一行包含一个整数n,含义如上文所示。接下来4n(n + 1)行,每行包含一个非负整数分别表示每一条道路每一个
方向的人流量信息。输入顺序:n(n + 1)个数表示所有从西到东方向的人流量,然后n(n + 1)个数表示所有从北到
南方向的人流量,n(n + 1)个数表示所有从东到西方向的人流量,最后是n(n + 1)个数表示所有从南到北方向的人
流量。对于每一个方向,输入顺序按照起点由北向南,若南北方向相同时由西到东的顺序给出(参见样例输入)。
Output
仅包含一个数,表示在最理想情况下每天上班高峰期间所有人爬坡所消耗的总体力和(即总体力和的最小值),结
果四舍五入到整数。
Sample Input
1
1
2
3
4
5
6
7
8
Sample Output
3
【样例说明】
样例数据见下图。
最理想情况下所有点的海拔如上图所示。
对于100%的数据:1 ≤ n ≤ 500,0 ≤ 流量 ≤ 1,000,000且所有流量均为整数。
80% n,m<=40
这个题的关键之处,就是得出一个结论:每个点要么为1要么为0,感性理解就可以了
然后就成了明显的最小割模型,割出每个点要么为1要么为0,然后就可以过80分了
对于全部数据,可以用对偶图做
考虑到这是一个emmmmmm 规则平面图(?应该是这个名字),可以构建其对偶图,用最短路来求最小割
对偶图
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
#define mp make_pair
#define fi first
#define se second
#define inf 0x3f3f3f3f
#define ll long long
#define N 260005
using namespace std;
int n,S,T,tot,hd[N],d[N],vis[N];
struct edge{int v,w,next;}e[N*];
void adde(int u,int v,int w){
e[++tot].v=v;
e[tot].w=w;
e[tot].next=hd[u];
hd[u]=tot;
}
char gc(){
static char s[],*p1,*p2;
if(p1==p2)p2=(p1=s)+fread(s,,,stdin);
if(p1==p2)return EOF;
return *p1++;
} void r(int &x){
x=;int f=;char ch=gc();
while(ch>''||ch<''){
if(ch=='-')f=-;
ch=gc();
}
while(ch>=''&&ch<='')x=x*+ch-'',ch=gc();
x*=f;
}
typedef pair<int,int>pii;
priority_queue<pii,vector<pii>,greater<pii> >q;
void dijkstra(){
for(int i=S;i<=T;i++)d[i]=inf;
d[S]=;q.push(mp(d[S],S));
while(!q.empty()){
pii u=q.top();q.pop();
if(vis[u.se])continue;
vis[u.se]=;
for(int i=hd[u.se];i;i=e[i].next){
int v=e[i].v;
if(d[v]<=d[u.se]+e[i].w)continue;
d[v]=d[u.se]+e[i].w;
q.push(mp(d[v],v));
}
}
printf("%d",d[T]);
}
int main(){
#ifdef wsy
freopen("data.in","r",stdin);
#else
freopen("altitude.in","r",stdin);
freopen("altitude.out","w",stdout);
#endif
r(n);
S=;T=n*n+;
int x,s,t; for(int i=;i<=n;i++)
r(x),s=i,t=T,
adde(i,T,x);
for(int i=;i<=n;i++)
for(int j=;j<=n;j++)
r(x),
s=(i-)*n+j,t=(i-)*n+j,
adde(s,t,x);
for(int i=;i<=n;i++)
r(x),
s=S,t=(n-)*n+i,
adde(S,t,x); for(int i=;i<=n;i++)
for(int j=;j<=n+;j++){
r(x);
if(j==){
s=S;t=(i-)*n+j;
adde(S,t,x);
}
else if(j==n+){
s=i*n;t=T;
adde(i*n,T,x);
}
else{
s=j+(i-)*n-;t=j+(i-)*n;
adde(s,t,x);
}
} for(int i=;i<=n;i++)
r(x),s=T,t=i,
adde(s,t,x);
for(int i=;i<=n;i++)
for(int j=;j<=n;j++)
r(x),
s=(i-)*n+j,t=(i-)*n+j,
adde(s,t,x);
for(int i=;i<=n;i++)
r(x),
s=(n-)*n+i,t=S,
adde(S,t,x); for(int i=;i<=n;i++)
for(int j=;j<=n+;j++){
r(x);
if(j==){
s=(i-)*n+j;t=S;
adde(S,t,x);
}
else if(j==n+){
s=T;t=i*n;
adde(s,t,x);
}
else{
s=j+(i-)*n;t=j+(i-)*n-;
adde(s,t,x);
}
}
dijkstra();
return ;
}
网络流
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
#define inf 0x3f3f3f3f
#define ll long long
#define N 1705
using namespace std;
int n,S,T,tot,mp[N][N],cur[N],vis[N],d[N],hd[N];
int dx[]={,,,-};
int dy[]={,-,,};
bool check(int x,int y){return x<=n&&y<=n&&x>=&&y>=;}
struct edge{int v,cap,next;}e[N*N*];
void adde(int u,int v,int c){
e[tot].v=v;
e[tot].next=hd[u];
e[tot].cap=c;
hd[u]=tot++;
}
bool bfs(){
queue<int>q;
memset(vis,,sizeof(vis));
q.push(S);d[S]=;vis[S]=;
while(!q.empty()){
int u=q.front();q.pop();
for(int i=hd[u];~i;i=e[i].next){
int v=e[i].v;
if(e[i].cap&&!vis[v]){
vis[v]=;
d[v]=d[u]+;
q.push(v);
}
}
}
return vis[T];
} int dfs(int u,int a){
if(u==T||!a)return a;
int fl=,f;
for(int &i=cur[u];~i;i=e[i].next){
int v=e[i].v;
if(e[i].cap&&d[v]==d[u]+&&(f=dfs(v,min(a,e[i].cap)))){
fl+=f;a-=f;
e[i].cap-=f;
e[i^].cap+=f;
if(!a)break;
}
}
return fl;
}
int main(){
#ifdef wsy
freopen("data.in","r",stdin);
#else
freopen("altitude.in","r",stdin);
freopen("altitude.out","w",stdout);
#endif
scanf("%d",&n);
memset(hd,-,sizeof(hd));
for(int i=;i<=n+;i++){
for(int j=;j<=n;j++){
int cnt=(i-)*(n+)+j;
scanf("%d",&mp[cnt][cnt+]);
}
}
for(int i=;i<=n;i++){
for(int j=;j<=n+;j++){
int cnt=(i-)*(n+)+j;
scanf("%d",&mp[cnt][cnt+n+]);
}
}
for(int i=;i<=n+;i++){
for(int j=;j<=n;j++){
int cnt=(i-)*(n+)+j;
scanf("%d",&mp[cnt+][cnt]);
}
}
for(int i=;i<=n;i++){
for(int j=;j<=n+;j++){
int cnt=(i-)*(n+)+j;
scanf("%d",&mp[cnt+n+][cnt]);
}
}
n++;S=;T=n*n+;
for(int i=;i<=n;i++)
for(int j=;j<=n;j++){
int id=(i-)*n+j;
if(id==n*n)continue;
for(int o=;o<;o++){
int nx=i+dx[o];
int ny=j+dy[o];
if(!check(nx,ny))continue;
int nd=(nx-)*n+ny;
//if(nd==1)continue;
adde(id,nd,mp[id][nd]);
adde(nd,id,);
// printf("%d %d %d\n",id,nd,mp[id][nd]);
}
}
adde(S,,inf);adde(,S,);
// printf("%d %d %d\n",S,1,inf);
adde(n*n,T,inf);adde(T,n*n,);
// printf("%d %d %d\n",n*n,T,inf);
int flow=;
while(bfs()){
for(int i=S;i<=T;i++)cur[i]=hd[i];
flow+=dfs(S,inf);
}
printf("%d",flow);
return ;
}
bzoj2007 NOI2010 网络流转对偶图的更多相关文章
- BZOJ2007 [Noi2010]海拔 【平面图最小割转对偶图最短路】
题目链接 BZOJ2007 题解 这是裸题啊,,要是考试真的遇到就好了 明显是最小割,而且是有来回两个方向 那么原图所有向右的边转为对偶图向下的边 向左的边转为向上 向下转为向左 向上转为向右 然后跑 ...
- [BZOJ2007][NOI2010]海拔(对偶图最短路)
首先确定所有点的海拔非0即1,问题转化成裸的平面图最小割问题,进而转化成对偶图最短路(同BZOJ1002). 这题的边是有向的,所以所有边顺时针旋转90度即可. 如下图(S和T的位置是反的). #in ...
- bzoj2007 NOI2010 海拔(对偶图)
80分(最小割)思路 先考虑如果没有题目中东南角为\(1\)那个限制的话会怎样. 那么只要让每个点的海拔都是\(0\)就行了.这样不论怎样走,最后的答案都是0. 然后再考虑那个东南角为\(1\)的限制 ...
- BZOJ2007 NOI2010 海拔 平面图转对偶图 最小割
题面太长啦,请诸位自行品尝—>海拔 分析: 这是我见过算法比较明显的最小割题目了,很明显对于某一条简单路径,海拔只会有一次变换. 而且我们要最终使变换海拔的边权值和最小. 我们发现变换海拔相当于 ...
- BZOJ1001 狼抓兔子(网络流转最短路:对偶图)
题意: 给一个如图形式的\(n*m\)的方格,从左上走到右下,给出边权,问分成两块所需的最小代价.\(n,m\leq1000\). 思路: 显然是个最小割,但是\(O(n^2m)\)的复杂度很高,虽然 ...
- Bzoj2007 [Noi2010]海拔(平面图最短路)
2007: [Noi2010]海拔 Time Limit: 20 Sec Memory Limit: 552 MBSubmit: 2742 Solved: 1318[Submit][Status] ...
- BZOJ2007——[Noi2010]海拔
1.题意:一个裸的最小割 2.分析:直接转成对偶图最短路就好了,水爆了!(雾) #include <queue> #include <cstdio> #include < ...
- bzoj千题计划129:bzoj2007: [Noi2010]海拔
http://www.lydsy.com/JudgeOnline/problem.php?id=2007 1.所有点的高度一定在0~1之间, 如果有一个点的高度超过了1,那么必定会有人先上坡,再下坡, ...
- 如何将网络流转化为内存流 C#
//将获取的文件流转化为内存流 public static MemoryStream ConvertStreamToMemoryStream(Stream stream) { MemoryStream ...
随机推荐
- bzoj千题计划244:bzoj3730: 震波
http://www.lydsy.com/JudgeOnline/problem.php?id=3730 点分树内对每个节点动态维护2颗线段树 线段树以距离为下标,城市的价值为权值 对于节点x的两棵线 ...
- Something about SeekingJob---TelInterview(电话面试)
昨天和今天分别收到两次电话面试,有一点小小感悟,遂注之. 作为一枚还未毕业的大三狗来说,我在想,找个实习真的是西天取金,必定要先经历九九八十一难吗(伤心)?所以在这里整理了电话面试遇到的问题: 集合框 ...
- php的函数参数按照从左到右来赋值
PHP 中自定义函数参数赋默认值 2012-07-07 13:23:00| 分类: php自定义函数,默|举报|字号 订阅 下载LOFTER我的照片书 | php自定义函数接受参数 ...
- web api 如何通过接收文件流的方式,接收客户端及前端上传的文件
服务端接收文件流代码: public async Task<HttpResponseMessage> ReceiveFileByStream() { var stream = HttpCo ...
- python全栈开发-常用模块的一些应用
一.random模块详解 1.概述 首先我们看到这个单词是随机的意思,他在python中的主要用于一些随机数,或者需要写一些随机数的代码,下面我们就来整理他的一些用法 2.常用方法 1. random ...
- Docker学习笔记 - Docker客户端和服务端
学习内容: Docker客户端和服务端的通讯方式:client和自定义程序 Docker客户端和服务端的连接方式:socket 演示Docker客户端和服务端之间用remote-api通讯:nc ...
- 【原生js实现一键回到顶部】
<!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title>& ...
- java stream 原理
java stream 原理 需求 从"Apple" "Bug" "ABC" "Dog"中选出以A开头的名字,然后从中选 ...
- [CodeForces 11D] A Simple Task - 状态压缩入门
状态压缩/Bitmask 在动态规划问题中,我们会遇到需要记录一个节点是否被占用/是否到达过的情况.而对于一个节点数有多个甚至十几个的问题,开一个巨型的[0/1]数组显然不现实.于是就引入了状态压缩, ...
- python--Selectors模块/队列
Selectors模块/队列 一 Selectors模块 IO多路复用实现机制 Win: select Linux:select(效率低) poll epoll(最好)默认选择epoll sele ...