洛谷P3356 火星探险问题(费用流)
和深海机器人问题差不多……看到有的大佬是用dp过的,强无敌……
考虑一下,把每一个点拆点,分别是$A_i$和$B_i$,连一条容量为$inf$,费用为$0$的边,表示可以随便走。如果有石头,再连一条边,容量为$1$,费用为$1$,表示只能走一次,且有$1$的价值。然后套路的建一个超级源和超级汇之后跑一个最大费用流即可
至于如何输出方案,可以一遍$dfs$,每一次只选一条边,然后判断一下这条边被选的次数是否大于等于反向边的流量,如果是说明已经不能再选,然后去选别的边
//minamoto
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#define inf 0x3f3f3f3f
using namespace std;
#define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
char buf[<<],*p1=buf,*p2=buf;
inline int read(){
#define num ch-'0'
char ch;bool flag=;int res;
while(!isdigit(ch=getc()))
(ch=='-')&&(flag=true);
for(res=num;isdigit(ch=getc());res=res*+num);
(flag)&&(res=-res);
#undef num
return res;
}
char sr[<<],z[];int C=-,Z;
inline void Ot(){fwrite(sr,,C+,stdout),C=-;}
inline void print(int x){
if(C><<)Ot();
while(z[++Z]=x%+,x/=);
while(sr[++C]=z[Z],--Z);
}
const int N=,M=;
int ver[M],Next[M],head[N],edge[M],flow[M],tmp[M],tot=;
int dis[N],disf[N],Pre[N],last[N],vis[N],maxflow=;
int ans[N],m=;
int id[][],mp[][];
int n,p,q,s,t,num=;
queue<int> Q;
inline void add(int u,int v,int f,int e){
ver[++tot]=v,Next[tot]=head[u],head[u]=tot,flow[tot]=f,edge[tot]=e;
ver[++tot]=u,Next[tot]=head[v],head[v]=tot,flow[tot]=,edge[tot]=-e;
}
bool spfa(){
memset(dis,0xef,sizeof(dis));
Q.push(s),dis[s]=,disf[s]=inf,Pre[t]=-;
while(!Q.empty()){
int u=Q.front();Q.pop();vis[u]=;
for(int i=head[u];i;i=Next[i]){
int v=ver[i];
if(flow[i]&&dis[v]<dis[u]+edge[i]){
dis[v]=dis[u]+edge[i],last[v]=i,Pre[v]=u;
disf[v]=min(disf[u],flow[i]);
if(!vis[v]) vis[v]=,Q.push(v);
}
}
}
return ~Pre[t];
}
void dinic(){
while(spfa()){
int u=t;maxflow+=disf[t];
while(u!=s){
flow[last[u]]-=disf[t];
flow[last[u]^]+=disf[t];
u=Pre[u];
}
}
}
void dfs(int x,int y){
int now=id[x][y],d0=id[x+][y],d1=id[x][y+];
for(int i=head[now+num];i;i=Next[i]){
if(tmp[i]>=flow[i^]) continue;
if(ver[i]==d0){
++tmp[i],ans[++m]=;
dfs(x+,y);
return;
}
if(ver[i]==d1){
++tmp[i],ans[++m]=;
dfs(x,y+);
return;
}
}
}
int main(){
n=read(),q=read(),p=read();
for(int i=;i<=p;++i)
for(int j=;j<=q;++j)
id[i][j]=++num;
s=,t=num*+;
for(int i=;i<=p;++i)
for(int j=;j<=q;++j)
mp[i][j]=read();
add(s,id[][],n,),add(id[p][q],t,n,);
for(int i=;i<=p;++i)
for(int j=;j<=q;++j){
if(mp[i][j]&) continue;
add(id[i][j],id[i][j]+num,inf,);
if(mp[i][j]) add(id[i][j],id[i][j]+num,,);
}
for(int i=;i<=p;++i)
for(int j=;j<=q;++j){
if(mp[i][j]&) continue;
if(i<p&&mp[i+][j]!=) add(id[i][j]+num,id[i+][j],inf,);
if(j<q&&mp[i][j+]!=) add(id[i][j]+num,id[i][j+],inf,);
}
dinic();
for(int i=;i<=maxflow;++i){
m=,dfs(,);
for(int j=;j<=m;++j) print(i),sr[++C]=' ',print(ans[j]),sr[++C]='\n';
}
Ot();
return ;
}
洛谷P3356 火星探险问题(费用流)的更多相关文章
- 洛谷P3356 火星探险问题(费用流)
题目描述 火星探险队的登陆舱将在火星表面着陆,登陆舱内有多部障碍物探测车.登陆舱着陆后,探测车将离开登陆舱向先期到达的传送器方向移动.探测车在移动中还必须采集岩石标本.每一块岩石标本由最先遇到它的探测 ...
- 洛谷 P3356 火星探险问题 【最大费用最大流】
输出方案好麻烦啊 拆点,石头的连(i,i',1,1)(i,i',inf,0)表示可以取一次价值1,空地直接连(i,i',inf,0),对于能走到的两个格子(不包括障碍),连接(i',j,inf,0), ...
- 洛谷 1004 dp或最大费用流
思路: dp方法: 设dp[i][j][k][l]为两条没有交叉的路径分别走到(i,j)和(k,l)处最大价值. 则转移方程为 dp[i][j][k][l]=max(dp[i-1][j][k-1][l ...
- 洛谷P4003 无限之环(费用流)
传送门 神仙题啊……不看题解我可能一年都不一定做得出来……FlashHu大佬太强啦 到底是得有怎样的脑回路才能一眼看去就是费用流啊…… 建好图之后套个板子就好了,那么我们着重来讨论一下怎么建图 首先, ...
- 洛谷P4012 深海机器人问题(费用流)
题目描述 深海资源考察探险队的潜艇将到达深海的海底进行科学考察. 潜艇内有多个深海机器人.潜艇到达深海海底后,深海机器人将离开潜艇向预定目标移动. 深海机器人在移动中还必须沿途采集海底生物标本.沿途生 ...
- 洛谷P2517 HAOI2010 订货 (费用流)
标准的费用流问题,关键在于巧妙地建模 一共有n个月份,源点设为0,汇点设为n+1 1.源点向所有月份连边,容量为正无穷,费用为该月进货的费用 2.每个月向下一个月连边,容量为仓库容量,费用为存货费用 ...
- 洛谷P4016 负载平衡问题 费用流
这道题还是很好的. 考察了选手对网络流的理解. 首先,任意两个相邻点之间的运货量时没有限制的. 我们可以将相邻点之间的流量建为无限大,单位费用设为 1,代表运输一个货物需耗费一个代价. 由于题目要求最 ...
- 洛谷.1251.餐巾计划问题(费用流SPFA)
题目链接 /* 每一天的餐巾需求相当于必须遍历某些点若干次 设q[i]为Dayi需求量 (x,y)表示边x容y费 将每个点i拆成i,i',由i'->T连(q[i],0)的边,表示求最大流的话一定 ...
- 洛谷P2770 航空路线问题(费用流)
题意 $n$个点从左向右依次排列,有$m$条双向道路 问从起点到终点,再从终点回到起点,在经过的点不同的情况下最多能经过几个点 Sol 首先,问题可以转化为求两条互不相交的路径,使得点数最多 为了满足 ...
随机推荐
- SqlConnection 无法设置连接超时
1.最有效的方法:对表格建立索引 2 在连接字符串中设置 Connection Timeout (默认15秒)3 设置 SqlCommand.CommandTimeout(默认是 30 秒)
- Pascal三角形
Pascal算法呢,很简单,因为有了推导公式nCr,而当我们刚刚接触一个事物时,面对要解决的问题,归纳分析得到规律,再通过编程,控制流程,对象,语言,方法,属性得到我们想要的结果.如果这次不是PAsc ...
- JAVA 用axis1 调用.NET的web service
1.去官网下载axis的jar包,我下的是1.4版本的 http://axis.apache.org/axis/java/releases.html 2.JAVA 代码: public void my ...
- linux之sort用法
sort命令是帮我们依据不同的数据类型进行排序,其语法及常用参数格式: sort [-bcfMnrtk][源文件][-o 输出文件] 补充说明:sort可针对文本文件的内容,以行为单位来排序. 参 数 ...
- zookpeer的安装与配置
zookpeer集群搭建: 集群搭建过程简介: 这里准3台服务器做zk(zookpeer下面简称zk)集群搭建: zk集群由一个leader和两个follower组成,对外端口默认为2181端口,关于 ...
- Clean小程序(控件消息)
一 . 准备工作 创建一个基于对话框的MFC项目 删除对话框上的工具 二 . 实现将seven图片贴到上面,按一下则换一张图片 1.在资源视图中添加位图资源,通过属性修改图片ID 2.将对话框拉长,防 ...
- Redis搭建(五):Cluster集群搭建
一.方案 1. 介绍 redis3.0及以上版本实现,集群中至少应该有奇数个节点,所以至少有三个节点,官方推荐三主三从的配置方式 使用哈希槽的概念,Redis 集群有16384个哈希槽,每个key通过 ...
- 外网访问vmvare
使用端口映射即可,以tplink wr886n为例, 方法如下: 1.打开浏览器,输入默认ip192.168.0.1回车登录: 2.登录对话框,输入 密码点击确定: 3.点击转发规则--虚拟服务器,点 ...
- AngularJS框架
http://www.runoob.com/angularjs/angularjs-intro.html
- sql server2008 跨服务器之间复制表数据
首先2个数据库要能互相访问,在本地数据库用 select * into 新表 from opendatasource('SQLOLEDB','Data Source=远程数据库IP;User ID=用 ...