[Bzoj 2547] [Ctsc2002] 玩具兵
2547: [Ctsc2002]玩具兵
Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 317 Solved: 152
[Submit][Status][Discuss]
Description
小明的爸爸给他买了一盒玩具兵,其中有 K个步兵,K个骑兵和一个天兵,个个高大威猛,形象逼真。盒子里还有一个M*N棋盘,每个格子(i,j)都有一个高度Hij,并且大得足以容纳所有的玩具兵。小明把所有的玩具兵都放到棋盘上去,突然想到了一种很有趣的玩法:任意挑选T个不同的格子,并给每个格子i规定一个重要值Ri,游戏的目标就是每次沿东南西北之一的方向把一个玩具兵移动到其相邻的格子中(但不能移动到棋盘外面去),最终使得每个挑选出的格子i上恰好有Ri个玩具兵。小明希望所有的玩具兵都在某个选定的格子中,因此他总是使选出的T个格子的重要值之和等于玩具兵的个数。为了增加难度,小明给玩具兵们的移动方式做了一些规定:
- 步兵只会往高处爬,因此如果两个格子A和B相邻,当且仅当格子A的高度小于或等于B,步兵才可以从A移动到B。
- 骑兵只会往低处跳,因此如果两个格子A和B相邻,当且仅当格子A的高度大于或等于B,骑兵才可以从A移动到B。
- 天兵技术全面,移动不受任何限制。
可是没玩几次,小明就发现这个游戏太难了,他常常玩了好半天也达不到目的。于是,他设计了一种“超能力”,每使用一次超能力的时候,虽然不能移动任何一个玩具兵,但可对它们进行任意多次交换操作,每次交换两个玩具兵。等这次超能力使用完后又可和平常一样继续移动这些玩具兵。借助强大的超能力,这个游戏是容易玩通的,但是怎样才能让使用超能力的次数最少呢?
Input
第一行包含四个整数:M,N,K,T (2<=M,N<=100, 1<=K<=50, 1<=T<=2K+1)
第二行包括2K+1个数对(xi,yi),代表各个玩具兵的初始位置。前K个代表步兵,接下来的K个代表骑兵,最后一个代表天兵。
第三行包含T个三元组(xi,yi,ri),第i组代表第i个目标格的位置和重要值。
以下M行,每行N个整数。其中第i行第j个数为即格子的高度Hij。高度是不超过100的正整数,注意:不同玩具兵的初始位置可能相同。输入数据保证无错,选定的T个格子的重要值之和保证等于2K+1。
Output
仅包含一行,即使用超能力的最小次数T。
Solution
观察到每次交换可以换无数次,所以每次一定是把步兵和骑兵换一下,相当于每个都走到无路可走的地方,然后换个职业继续走。
所以对于每个玩具兵(先不考虑天兵),都 Spfa 瞎搞出到每个点最少要交换的次数,也就是说,至少要交换 _dis[i][j] 次才能到达 (i,j)。
然后二分答案,二分出交换的次数 mid,然后对于每个玩具兵,向交换次数小于 mid 的终点连边,然后跑最大流即可。
注意最后要加上二分出的 mid,意义就是天兵每次都可以替代一个玩具兵走到终点,然后换它们俩就好。
Code
// By YoungNeal #include<queue> #include<cstdio> #include<cstring> ]; int s,t,maxflow; ]; ][]; ][]; ][]; // 记录交换了几次 dis[i][j]->第i个兵到第j个目标 int m,n,k,T,ans,cnt; ][]; ][][]; // _dis[i][j]->从当前的点到(i,j)最少交换次数 ][][]; // in[i][j][p]->当前点到(i,j)职业为p是否在队列 ,,,},dy[]={,,,-}; struct Node{ int x,y,o; }; struct Edge{ int to,nxt,flow; }edge[]; void add(int x,int y,int z){ edge[++cnt].to=y; edge[cnt].nxt=head[x]; edge[cnt].flow=z; head[x]=cnt; } void spfa(int now,int xx,int yy,int cnt){ std::queue<Node> q; memset(,sizeof in); memset(_dis,0x3f,sizeof _dis); _dis[xx][yy][cnt]=; q.push((Node){xx,yy,cnt}); while(q.size()){ int x=q.front().x; int y=q.front().y; int o=q.front().o; q.pop(); ; ;k<;k++){ int nx=x+dx[k]; int ny=y+dy[k]; int nowdis,oo; ||nx>m||ny<||ny>n) continue; &&height[nx][ny]>=height[x][y])||(o==&&height[nx][ny]<=height[x][y])) nowdis=_dis[x][y][o],oo=o; ,oo=o^; if(_dis[nx][ny][oo]>nowdis){ _dis[nx][ny][oo]=nowdis; ,q.push((Node){nx,ny,oo}); } } } ;i<=T;i++){ dis[now][i]=std::min(_dis[goal[i][]][goal[i][]][],_dis[goal[i][]][goal[i][]][]); } } void clear(){ maxflow=; cnt=;s=k*+T+;t=s+; memset(edge,,sizeof edge); memset(head,,sizeof head); } bool bfs(){ std::queue<int> q; memset(d,,sizeof d); q.push(s);d[s]=; while(q.size()){ int u=q.front();q.pop(); for(int i=head[u];i;i=edge[i].nxt){ int to=edge[i].to; if(d[to]) continue; if(!edge[i].flow) continue; d[to]=d[u]+; q.push(to); ; } } ; } int dinic(int now,int flow){ if(now==t) return flow; int rest=flow,k; for(int i=head[now];i;i=edge[i].nxt){ if(!rest) return flow; int to=edge[i].to; if(!edge[i].flow) continue; ) continue; k=dinic(to,std::min(rest,edge[i].flow)); ; edge[i].flow-=k; edge[i^].flow+=k; rest-=k; } return flow-rest; } bool check(int mid){ clear(); ;i<=k*;i++){ ;j<=T;j++){ ,),add(j+k*,i,); } } ;i<=k*;i++) add(s,i,),add(i,s,); ;i<=T;i++) add(i+k*,t,goal[i][]),add(t,i+k*,); ; while(bfs()) while(flow=dinic(s,0x3f3f3f3f)) maxflow+=flow; ; } signed main(){ scanf("%d%d%d%d",&m,&n,&k,&T); ;i<=k*+;i++) scanf(],&toy[i][]); ;i<=T;i++) scanf(],&goal[i][],&goal[i][]); ;i<=m;i++){ ;j<=n;j++) scanf("%d",&height[i][j]); } ;i<=(k<<);i++) spfa(i,toy[i][],toy[i][],(i>k)); ,r=(k<<)+; while(l<=r){ ; ; ; } printf("%d\n",ans); ; }
[Bzoj 2547] [Ctsc2002] 玩具兵的更多相关文章
- BZOJ 2547: [Ctsc2002]玩具兵(二分答案+二分图匹配)
传送门 解题思路 可以发现天兵不用管,答案的一个上界是\(2*k\),就是天兵一个个换.刚开始写了个拆\(6\)点的网络流,调了半天发现自己假了..说说正解,首先可以发现交换士兵其实就是种类的交换,那 ...
- BZOJ2547 CTSC2002玩具兵(最短路径+二分答案+最大流)
先不考虑只有一个显得有些特殊的天兵. 可以发现超能力的作用实质上是使兵更换职业.每一个兵到达某个位置最少需要更换职业的次数是彼此独立的,因为如果需要某两人互换职业可以使他们各自以当前职业到达需要到的地 ...
- bzoj2547: [Ctsc2002]玩具兵
划了一天水,其实我还是有点愧疚的. 传送门 其实是水题,然而我真是太蠢了... 首先不考虑天兵,其他兵要到一个点去一定是通过它-另一种兵-它……这样多次交换的,并且交换对象是无所谓的,和它换的兵最终会 ...
- [BZOJ 2547] 玩具兵
Link: BZOJ 2547 传送门 Solution: 很容易通过解可行性的单调性想到二分答案,接下来考虑如何验证解 发现一个很奇妙的条件:步兵和骑兵的个数相同 因此交换位置时不用考虑可行性,保证 ...
- Bzoj 1055: [HAOI2008]玩具取名 (区间DP)
Bzoj 1055: [HAOI2008]玩具取名 (区间DP) 题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1055 区间动态规划和可 ...
- [bzoj2547]玩具兵<Spfa+二分+匈牙利算法>
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2547 挺有意思的一道题,这道题可以划分成几个小题....... 题目大意: 三个兵种在一个 ...
- BZOJ 1010: [HNOI2008]玩具装箱toy [DP 斜率优化]
1010: [HNOI2008]玩具装箱toy Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 9812 Solved: 3978[Submit][St ...
- BZOJ 1010: [HNOI2008]玩具装箱toy 斜率优化DP
1010: [HNOI2008]玩具装箱toy Description P教授要去看奥运,但是他舍不下他的玩具,于是他决定把所有的玩具运到北京.他使用自己的压缩器进行压缩,其可以将任意物品变成一堆,再 ...
- bzoj 1054 移动玩具
题目连接 http://www.lydsy.com/JudgeOnline/problem.php?id=1054 移动玩具 Description 在一个4*4的方框内摆放了若干个相同的玩具,某人想 ...
随机推荐
- ARM-LINUX自动采集温湿度传感器数据
开机root自动登录 如果想在超级终端输入回车,登录后执行,则可以在/etc/profile中加入命令: 如果实现开机自动登录,在/etc/inittab中修改,每个开发板修改的方式可能都不同. ht ...
- 剑指offer 第九天
35.数组中的逆序对 在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对.输入一个数组,求出这个数组中的逆序对的总数P.并将P对1000000007取模的结果输出. 即输出 ...
- VBR与CBR的区别是什么?
VBR是动态码率.CBR是静态码率. VBR(Variable Bitrate)动态比特率.也就是没有固定的比特率,压缩软件在压缩时根据音频数据即时确定使用什么比特率,这是以质量为前提兼顾文件大小的方 ...
- Android Parcelable和Serializable的区别
本文主要介绍Parcelable和Serializable的作用.效率.区别及选择,关于Serializable的介绍见Java 序列化的高级认识. 1.作用 Serializable的作用是为了保存 ...
- ORA-00904:"T1"."AREA_ID" :标识符无效
1.错误描述 ORA-00904:"T1"."AREA_ID" :标识符无效 00904 . 00000 - "%s:invalid identifi ...
- Django学习-12-模板继承
对于一下3个HTML页面 url(r'^templates1/', views.templates1), url(r'^templates2/', views.temp ...
- C#图解教程 第十三章 委托
委托 什么是委托委托概述声明委托类型创建委托对象给委托赋值组合委托为委托添加方法从委托移除方法调用委托委托示例调用带返回值的委托调用带引用参数的委托匿名方法 使用匿名方法匿名方法的语法 Lambda ...
- 深究ASP.NET Session
Session 本质 & 访问方法 Session 本质 是 HttpSessionState 类 link Session 访问方法 HttpContext.Session Page.Ses ...
- LVS-NAT模式的配置详解
由于实验室拟态存储的项目需要通过NAT模式来映射NFS服务器已实现负载均衡的目的,通过调研了多种负载均衡机制,笔者最终选择了LVS的NAT模式来实现需求,接下来通过博客来记录一下LVS-NAT模式的配 ...
- c#多线程同步之EventWaitHandle再次使用
/// <summary> /// 文件传输器,用来获取全文文件,自动根据全文文件数量,开启一定数量的线程,采用生产者消费模式 /// </summary> public cl ...