hdu2732 最大流+拆点
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2732
题目给定一个场景,有n*m个方格,每个方格代表一个柱子,一个柱子可以承受不同次数的跳跃,开始时图中给定一些地方有蜥蜴,并且给定蜥蜴最多跳跃的步长,只要跳到方格之外就能安全,而且每只蜥蜴不能在同一个地方重合,每次蜥蜴跳离一个地方这个地方的柱子就的承受次数就会减一,问最终会有多少只蜥蜴不能跳出迷宫。
这个问题可以这样思考,每次蜥蜴跳出一个位置之后这个位置的“资源”就会减少1,而这个减少之后的“资源”不可以再利用,而且涉及到点之间的转移,这在图论中和最大流很相似,所以我们想到可不可以将点转化成状态,地图中的每一个位置(i,j)(0<=i,j<n)可以通过i*m+j+1转化成[1,n*m]闭区间之内的位置,所以我们可以把这个设为他的id,可以将点位置拆开成两个,一个是id,表示没有转移时的状态,另一个点是id+n*m,表示这个点拆开之后的另一个状态。设置一个超级源和一个超级汇。
转换策略如下:
①、如果一个点位置(i,j)值num大于0,那么可以连边(id,id+n*m,num),表示最多有num次“流”在这个位置转换,num个用完也就代表不能发生转换,也就是这个位置不能站蜥蜴了。
②、如果一个位置通过跳跃d可以到达外围就设置边(id,T,inf),就是把这个位置和超级汇连接起来,并且不限制从这里通过的蜥蜴的数量。
③、如果一个位置有蜥蜴,我们可以把这个位置和超级源连接在一起,也就是(S,id,1)1表示在这个位置有一只蜥蜴出发。就相当于把蜥蜴放在一个源点,蜥蜴数量便是源点流量。
④、两个位置之间的距离(横纵坐标绝对值之差)如果小于d那就可以转换,注意连的边是(id+n*m,id2,1),因为在他跳出当前位置时必须当前位置的承受容量减一,所以必须重跳完之后的状态转移。
基本思想就是拆点。需要慎重思考转移的方式。
#include<bits/stdc++.h>
using namespace std;
typedef unsigned int ui;
typedef long long ll;
typedef unsigned long long ull;
#define pf printf
#define mem(a,b) memset(a,b,sizeof(a))
#define prime1 1e9+7
#define prime2 1e9+9
#define pi 3.14159265
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define scand(x) scanf("%llf",&x)
#define f(i,a,b) for(int i=a;i<=b;i++)
#define scan(a) scanf("%d",&a)
#define mp(a,b) make_pair((a),(b))
#define P pair<int,int>
#define dbg(args) cout<<#args<<":"<<args<<endl;
#define inf 0x7ffffff
inline int read(){
int ans=,w=;
char ch=getchar();
while(!isdigit(ch)){if(ch=='-')w=-;ch=getchar();}
while(isdigit(ch))ans=(ans<<)+(ans<<)+ch-'',ch=getchar();
return ans*w;
}
const int maxn=;
const int maxm=;
struct flow{
int s,t;
int head[maxn],nxt[maxm],d[maxn],cur[maxn];//cur当前弧优化
bool vis[maxn];
struct node{
int u,v,w;
}p[maxm];
int e;
void init()
{
e=;
mem(head,-);
mem(nxt,-);
}
void addedge(int u,int v,int w)//顺带添加反向边
{
p[e].u=u;
p[e].v=v;
p[e].w=w;
nxt[e]=head[u];
head[u]=e++;
p[e].u=v;
p[e].v=u;
p[e].w=;
nxt[e]=head[v];
head[v]=e++;
}
bool bfs(int src,int sink)//确定bfs序
{
mem(vis,);
mem(d,);
d[src]=;
vis[src]=;
queue<int> q;
q.push(src);
while(!q.empty())
{
int cur=q.front();
q.pop();
for(int i=head[cur];~i;i=nxt[i])
{
int v=p[i].v;
if(!vis[v]&&p[i].w)//确定这个点没有被标号,并且不是反向边
{
vis[v]=;
d[v]=d[cur]+;
q.push(v);
}
}
}
if(d[sink])return true;
return false;
}
int dfs(int s,int flow)
{
if(s==t)return flow;
int used=;
for(int& i=cur[s];~i;i=nxt[i])
{
int v=p[i].v,w=p[i].w;
if(d[v]==d[s]+&&w>)//根据Dinic算法的思想,只能走正向的、bfs序大一的边
{
int tmp=dfs(v,min(flow-used,w));
if(tmp>)
{
p[i].w-=tmp;//更新正向边的流量以及反向边的流量,
p[i^].w+=tmp;//正向边是偶数,它对应的反向边就是正向边+1
used+=tmp;//从一个点出发最多的流量是flow,用掉的流量需要更新
if(used==flow)break;
}
}
}
if(!used)d[s]=;//从该点出发的流不能被使用,所以这个点在这次搜索中被丢弃
return used;
}
int dinic()
{
int ans=;
while(bfs(s,t))
{
memcpy(cur,head,sizeof(head));
ans+=dfs(s,inf);
}
return ans;
}
}a;
int d;
int t;
char s[];
int main()
{
//freopen("input.txt","r",stdin);
//freopen("output.txt","w",stdout);
std::ios::sync_with_stdio(false);
t=read();
int n,m;
int kase=;
while(t--)
{
a.init();
int cnt=;
n=read(),d=read();
f(i,,n-)
{
scanf(" %s",s);
if(i==)
{
m=strlen(s);
// a.n=2*n*m+2;//最大流中点的数量设置
a.s=;
a.t=*n*m+;//设置超级源与超级汇
}
f(j,,m-)
{
int num=s[j]-'';
if(num>)//将大于零的格子拆开成两个格子,并连线,
{
int id=i*m+j+;
a.addedge(id,id+n*m,num);
if(i-d<||i+d>=n||j-d<||j+d>=m)
{
a.addedge(id+n*m,a.t,inf);//可以到达安全地点,且流的大小不限制
}
else
{
f(k,,n-)//由于图的大小不大,所以可以枚举每一个位置检查是否可行
f(l,,m-)
{
int id2=k*m+l+;
if(id==id2)continue;
if(abs(i-k)+abs(j-l)<=d)
a.addedge(id+n*m,id2,inf);//从id位置能够跳到id2位置,但是记住一定是在id位置少1之后的结点上
}
}
}
}
}
f(i,,n-)
{
scanf(" %s",s);
f(j,,m-)
{
if(s[j]=='L')//记录蜥蜴的数量并与超级源连线,
{
cnt++;
int id=i*m+j+;
a.addedge(a.s,id,);
}
}
}
int ans=cnt-a.dinic();
if(ans==)pf("Case #%d: no lizard was left behind.\n",++kase);
else if(ans==)pf("Case #%d: 1 lizard was left behind.\n",++kase);
else pf("Case #%d: %d lizards were left behind.\n",++kase,ans); }
}
hdu2732 最大流+拆点的更多相关文章
- poj 3498 March of the Penguins(最大流+拆点)
题目大意:在南极生活着一些企鹅,这些企鹅站在一些冰块上,现在要让这些企鹅都跳到同一个冰块上.但是企鹅有最大的跳跃距离,每只企鹅从冰块上跳走时会给冰块造成损害,因此企鹅跳离每个冰块都有次数限制.找出企鹅 ...
- poj 2391 Ombrophobic Bovines, 最大流, 拆点, 二分, dinic, isap
poj 2391 Ombrophobic Bovines, 最大流, 拆点, 二分 dinic /* * Author: yew1eb * Created Time: 2014年10月31日 星期五 ...
- hdu2732 Leapin' Lizards 最大流+拆点
Your platoon of wandering lizards has entered a strange room in the labyrinth you are exploring. As ...
- 最大流拆点——hdu2732,poj3436
一种很普遍的做法就是把一个带有容量的点拆成两个点,一个入点一个出点,链接两个点的边的权值为这个点的容量 hdu3732 #include<cstdio> #include<cstri ...
- hdu4289 最小割最大流 (拆点最大流)
最小割最大流定理:(参考刘汝佳p369)增广路算法结束时,令已标号结点(a[u]>0的结点)集合为S,其他结点集合为T=V-S,则(S,T)是图的s-t最小割. Problem Descript ...
- BZOJ-1877 晨跑 最小费用最大流+拆点
其实我是不想做这种水题的QWQ,没办法,剧情需要 1877: [SDOI2009]晨跑 Time Limit: 4 Sec Memory Limit: 64 MB Submit: 1704 Solve ...
- BZOJ-1070 修车 最小费用最大流+拆点+略坑建图
1070: [SCOI2007]修车 Time Limit: 1 Sec Memory Limit: 162 MB Submit: 3624 Solved: 1452 [Submit][Status] ...
- hdu 4289 最大流拆点
大致题意: 给出一个又n个点,m条边组成的无向图.给出两个点s,t.对于图中的每个点,去掉这个点都需要一定的花费.求至少多少花费才能使得s和t之间不连通. 大致思路: 最基础的拆点最大 ...
- 洛谷 P2764 最小路径覆盖问题【最大流+拆点+路径输出】
题目链接:https://www.luogu.org/problemnew/show/P2764 题目描述 «问题描述: 给定有向图G=(V,E).设P 是G 的一个简单路(顶点不相交)的集合.如果V ...
随机推荐
- Binder机制简析(三)
注册Service Service组件运行在Server进程中,首先要将Service注册到Service Manager中,再启动一个Binder线程池来等待和处理Client的通信请求. 注册过程 ...
- 烧钱时代终结!O2O还能玩啥花样?
最终的最终,饱受亏损.烧钱玩补贴等争议的美团还是追随滴滴/快的.赶集/58的步伐,与大众点评愉快的在一起了!美团和大众点评作为O2O行业的领军企业,都因为不堪忍受持续地投入却不见回报的模式而不得不放低 ...
- java的23种设计模式之建造者模式
场景和本质 场景 本质 案例 原理 应用场景 场景和本质 场景 我们要建造一个复杂的产品.比如:神州飞船,Iphone.这个复杂的产品的创建.有这样一个问题需要处理:装配这些子组件是不是有个步骤问题? ...
- PHP 解决对文件操作的高并发问题
解决方案: 对文件进行加锁时,设置一个超时时间.超时设置为1ms,如果这段时间内没有获得锁,就反复获得,直到获得对文件的操作权为止.如果超市限制已到,就必须马上退出,让出锁让其他进程进行操作. ...
- C++走向远洋——25(项目二,游戏类)
*/ * Copyright (c) 2016,烟台大学计算机与控制工程学院 * All rights reserved. * 文件名:game.cpp * 作者:常轩 * 微信公众号:Worldhe ...
- Grafana+Prometheus监控mysql性能
#cmd /usr/local 今天讲一下如何监控服务器中的mysql数据库的性能 一.数据库操作 1.mysql启动 #service mysqld start #启动数据库 #service my ...
- Pro SQL Server Internal (Dmitri Korotkev)电子书翻译P8-14(12w)
数据行与数据列 数据库的控件逻辑上分成8KB的页,这些页从0开始,连续排序,对特定的文件ID和页码有借鉴意义.页码编号一定是连续的,当SQL服务器中的数据库文件增加时,新的数据页从最高的页码开始编码. ...
- AVCaptureInput和AVCaptureOutput子类介绍
AVCaptureInput AVCaptureDeviceInput:用于从AVCaptureDevice对象捕获数据. AVCaptureScreenInput:从macOS屏幕上录制的一种捕获输 ...
- 原本准备的 event loop 分享
基础介绍 Stack 栈 一种先入后出的数据结构. 两个基本操作: 推入,弹出 Queue 队列 一种先入先出的数据结构 操作: 入队,出队 两种任务: 同步任务,异步任务 同步任务: 在调用栈中等待 ...
- 授人以渔式解析原生JS写轮播图
需求与分析 需求:循环无缝自动轮播五张图,按左右箭头可以手动切换图片,鼠标点击轮播图下面按钮 1 2 3 4 5会跳转到对应的第1 2 3 4 5张图片.鼠标放到轮播图的图片上时不再自动轮播并且左右箭 ...