关于这道题, 我们可以发现移动顺序不会改变答案, 具体来说, 我们有以下引理成立:

  • 对于一个移动过程中的任意一个移动, 若其到达的位置上有一个棋子, 则该方案要么不能将所有棋子移动到最终位置, 要么可以通过改变顺序使这一次移动合法

证明:

考虑到达位置上的那个棋子, 如果它没有到达最终位置, 则我们考虑将该棋子移至下一步, 如果下一步还有没有到达最终位置的棋子, 则也移动它

否则直接调换这两个棋子的移动顺序即可

好的我们去除了题目中的要求: 「移动过程中不能出现多颗棋子同时在某一格的情况」, 接下来考虑题目被我们转化成了什么样子:

给定\(k\)个起始点和它们到达\(k\)个终点的步数, 求一种移动方案, 使得这种移动方案能将所有起始点移动到终点(保证有方案), 其次使得所花费的步数最少.

于是我们把这道题目转化为了一个费用流问题, 具体的, 我们建立超级源点\(S\), 超级汇点\(T\), 接下来连接三类边

  1. \(S\rightarrow\)所有起始点, 这类边容量为1, 费用为0

  2. 每一个起始点\(\rightarrow\)每一个它能够到达的终点, 这类边容量为1, 费用为所消耗的步数

  3. 所有终点\(\rightarrow T\), 这类边容量为1, 费用为0

在新图上跑费用流即可AC

要是这道题有这么简单就好了

如果你使用了一般的EK+SPFA, 你会像我这样:

接下来我们考虑改进算法, ouuan在这篇帖子中说道:

常见费用流算法(把 Dinic 的 BFS 改成求最短路)复杂度上界是 \(O(nmf)\),其中 \(f\) 是最大流。

于是我们点进了下面的链接学习了那种方法并且AC本题

我不会那种方法>_< 于是使用了Dijkstra跑最短路, 事实上一般的Dijkstra是不能跑的, 但是我在费用流的题解中找到了这种神仙做法

具体来说, 我们定义势函数\(h(i)\)使得\(e'(u,v)=e(u,v)+h(u)-h(v)\), 最后对最短路的影响可以强行考虑掉, 且\(e'(u,v)\)恒非负, 就可Dijkstra了

接下来我们发现\(h(i)=mindis(u)\)是成立的, 但那样的话你还要跑SPFA求最短路

因此我们转而考虑\(h(i)=mindis_{round-1}(u)\), 其中\(mindis_{round-1}(u)\)指上一轮\(S \rightarrow u\)的最短路(不存在为0), 我们发现这也是成立的, 具体来说, 我们考虑每条边\(e(u,v)\).

  • 若\(e(u,v)\)在上一次增广时存在, 那么显然满足性质
  • 否则\(e(u,v)\)在最短路上, 也可证明\(e'(u,v) \geq 0\)

于是我们的势算法成立, 用Dijkstra替换SPFA即可在luogu上AC本题

#pragma GCC diagnostic error "-std=c++11"
#pragma GCC target("avx")
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#pragma GCC optimize("-fgcse")
#pragma GCC optimize("-fgcse-lm")
#pragma GCC optimize("-fipa-sra")
#pragma GCC optimize("-ftree-pre")
#pragma GCC optimize("-ftree-vrp")
#pragma GCC optimize("-fpeephole2")
#pragma GCC optimize("-ffast-math")
#pragma GCC optimize("-fsched-spec")
#pragma GCC optimize("unroll-loops")
#pragma GCC optimize("-falign-jumps")
#pragma GCC optimize("-falign-loops")
#pragma GCC optimize("-falign-labels")
#pragma GCC optimize("-fdevirtualize")
#pragma GCC optimize("-fcaller-saves")
#pragma GCC optimize("-fcrossjumping")
#pragma GCC optimize("-fthread-jumps")
#pragma GCC optimize("-funroll-loops")
#pragma GCC optimize("-fwhole-program")
#pragma GCC optimize("-freorder-blocks")
#pragma GCC optimize("-fschedule-insns")
#pragma GCC optimize("inline-functions")
#pragma GCC optimize("-ftree-tail-merge")
#pragma GCC optimize("-fschedule-insns2")
#pragma GCC optimize("-fstrict-aliasing")
#pragma GCC optimize("-fstrict-overflow")
#pragma GCC optimize("-falign-functions")
#pragma GCC optimize("-fcse-skip-blocks")
#pragma GCC optimize("-fcse-follow-jumps")
#pragma GCC optimize("-fsched-interblock")
#pragma GCC optimize("-fpartial-inlining")
#pragma GCC optimize("no-stack-protector")
#pragma GCC optimize("-freorder-functions")
#pragma GCC optimize("-findirect-inlining")
#pragma GCC optimize("-fhoist-adjacent-loads")
#pragma GCC optimize("-frerun-cse-after-loop")
#pragma GCC optimize("inline-small-functions")
#pragma GCC optimize("-finline-small-functions")
#pragma GCC optimize("-ftree-switch-conversion")
#pragma GCC optimize("-foptimize-sibling-calls")
#pragma GCC optimize("-fexpensive-optimizations")
#pragma GCC optimize("-funsafe-loop-optimizations")
#pragma GCC optimize("inline-functions-called-once")
#pragma GCC optimize("-fdelete-null-pointer-checks")
#include<bits/stdc++.h>
using namespace std;
namespace mcmf {
const int N=1002; const int M=500*502*2+1; const int inf=0x3f3f3f3f;
int tot = 1, head[N], Next[M * 2], ver[M * 2], edge[M * 2], cost[M * 2];
int dis[N], h[N], lst[N], pre[N], C, n;
#define pi pair<int,int>
inline void _add(int u, int v, int c, int w) {
Next[++tot] = head[u], head[u] = tot, ver[tot] = v, edge[tot] = c, cost[tot] = w;
}
inline void add(int u, int v, int c, int w) {
_add(u, v, c, w), _add(v, u, 0, -w);
}
void Dijkstra(int s) {
priority_queue<pi, vector<pi>, greater<pi> > q;
for(; !q.empty(); q.pop());
fill(dis, dis + 1 + n, -1);
dis[s] = 0, q.push(pi(0, s));
while(!q.empty()) {
pi now = q.top(); q.pop();
int u = now.second;
if(dis[u] < now.first) continue;
for(int i = head[u]; i; i = Next[i]) {
static int v; v = ver[i];
if(!edge[i]) continue;
if(dis[v] < 0 || dis[v] > dis[u] + cost[i] + h[u] - h[v]) {
dis[v] = dis[u] + cost[i] + h[u] - h[v];
pre[v] = u, lst[v] = i;
q.push(pi(dis[v], v));
}
}
}
}
int solve(int s, int t) {
memset(h,0,sizeof(h)); int d=inf;
while(1){
Dijkstra(s); if(dis[t] < 0) break;
for(register int i = 1; i <= n; ++i) h[i] += (dis[i] != -1) ? dis[i] : 0; d=inf;
for(int u = t; u != s; u = pre[u]) edge[lst[u]]<d && (d=edge[lst[u]]); C += h[t] * d;
for(int u = t; u != s; u = pre[u]) edge[lst[u]] -= d, edge[lst[u] ^ 1] += d;
}
return C;
}
}
const int _=501,__=101;
int n,m,k,a,b;
int un[__][__],dis[__][__];
struct pos{
int x,y;
}st[_], ed[_];
queue<pos> Q;
int dx[8]={1,1,-1,-1,1,1,-1,-1}, dy[8]={1,-1,1,-1,1,-1,1,-1};
#define in(a) (a.x>=1 && a.x<=n && a.y>=0 && a.y<=m && !un[a.x][a.y])
void getdis(int s){
Q.push(st[s]); dis[st[s].x][st[s].y]=0; pos x; int d;
while(!Q.empty()){
x=Q.front(); d=dis[x.x][x.y]; Q.pop();
for(int i=0;i<8;++i){
x.x+=dx[i]; x.y+=dy[i];
(dis[x.x][x.y]==-1) && in(x) && (Q.push(x),dis[x.x][x.y]=d+1);
x.x-=dx[i]; x.y-=dy[i];
}
}
}
char get(){char c=getchar(); while(c!='*' && c!='.') c=getchar(); return c;}
int main(){
scanf("%d%d%d%d%d",&n,&m,&k,&a,&b);
for(register int i=1;i<=n;++i) for(int j=1;j<=m;++j) {
char ch=get(); un[i][j]=(ch=='*');
}
for(register int i=0;i<4;++i) dx[i]*=a,dy[i]*=b;
for(register int i=4;i<8;++i) dx[i]*=b,dy[i]*=a;
for(register int i=1;i<=k;++i) scanf("%d%d",&st[i].x,&st[i].y);
for(register int i=1;i<=k;++i) scanf("%d%d",&ed[i].x,&ed[i].y);
for(register int i=1;i<=k;++i) {
memset(dis,-1,sizeof(dis)); getdis(i);
for(int j=1;j<=k;++j) if(dis[ed[j].x][ed[j].y]!=-1) mcmf::add(i+1,j+k+1,1,dis[ed[j].x][ed[j].y]);
}
for(int i=1;i<=k;++i) mcmf::add(1,i+1,1,0),mcmf::add(i+k+1,2*k+2,1,0);
mcmf::n=2*k+2; printf("%d\n",mcmf::solve(1,2*k+2));
}

题解 Luogu P2499: [SDOI2012]象棋的更多相关文章

  1. [题解] Luogu P5446 [THUPC2018]绿绿和串串

    [题解] Luogu P5446 [THUPC2018]绿绿和串串 ·题目大意 定义一个翻转操作\(f(S_n)\),表示对于一个字符串\(S_n\), 有\(f(S)= \{S_1,S_2,..., ...

  2. 题解 luogu P1144 【最短路计数】

    本蒟蒻也来发一次题解第一篇请见谅 这个题有几个要点 1.无向无权图,建图的时候别忘记建来回的有向边[因此WA掉1次 2.无权嘛,那么边长建成1就好了2333333 3.最短路采用迪杰斯特拉(别忘用堆优 ...

  3. [SDOI2012]象棋

    题解: sd的题目也真是奇怪 第一题有了最短路第二题还有 第二题有了网络流第三题还有 显然是可以网络流的 但考虑每个点只能存在一个这个条件 刚开始我以为是建分层图..但发现这个时间复杂度太高了 其实我 ...

  4. 【洛谷题解】P2303 [SDOi2012]Longge的问题

    题目传送门:链接. 能自己推出正确的式子的感觉真的很好! 题意简述: 求\(\sum_{i=1}^{n}gcd(i,n)\).\(n\leq 2^{32}\). 题解: 我们开始化简式子: \(\su ...

  5. 题解 Luogu P1110 【[ZJOI2007]报表统计】

    感谢 @cmy962085349 提供的hack数据,已经改对了. 先声明,我好像是题解里写双$fhq$ $treap$里唯一能过的...(最后两个点啊) 思路:首先看题目,$MIN_GAP_SORT ...

  6. 题解 Luogu P3370

    讲讲这题的几种做法: 暴力匹配法 rt,暴力匹配,即把字符串存起来一位一位判相等 时间复杂度$ O(n^2·m) $ 再看看数据范围 \(n\le10^5,m\le10^3\) 当场爆炸.当然有暴力分 ...

  7. 题解 Luogu P3623 [APIO2008]免费道路

    [APIO2008]免费道路 题目描述 新亚(New Asia)王国有 N 个村庄,由 M 条道路连接.其中一些道路是鹅卵石路,而其它道路是水泥路.保持道路免费运行需要一大笔费用,并且看上去 王国不可 ...

  8. luogu 2051 中国象棋

    非常好的dp,锻炼思维 f[i][j][k] 前i行有j列放1,k列放2 #include<bits/stdc++.h> #define int long long #define rep ...

  9. luogu P2303 [SDOi2012]Longge的问题

    传送门 \[\sum_{i=1}^{n}\gcd(i,n)\] 考虑枚举所有可能的gcd,可以发现这一定是\(n\)的约数,当\(\gcd(i,n)=x\)时,\(gcd(\frac{i}{x},\f ...

随机推荐

  1. vue - 子组件向父组件 传递方法和参数

    1,子组件 TodoItem.vue  : <template>   <div class="todo-item" :class="{'is-compl ...

  2. 在普通WEB项目中使用Spring

    Spring是一个对象容器,帮助我们管理项目中的对象,那么在web项目中哪些对象应该交给Spring管理呢? 项目中涉及的对象 ​ 我们回顾一下WEB项目中涉及的对象 Servlet Request ...

  3. 应用于Oculus Quest的VR头显应用

    项目需要一个VR头显项目来展示算法成果,设备为Oculus Quest一体机,基于android平台(平台要切换为android),体验了下设备效果还行,但还是有点沙窗效应.记录一下开发流程. 先贴个 ...

  4. Asp.net mvc+EF+Sql Server2008数据库缓存依赖

    1.开启数据库缓存依赖功能(开启对数据库中表Article和ArticleType的缓存) (注:)如果要配置SqlCacheDependency,则需要以命令行的方式执行. aspnet_regsq ...

  5. thinkphp调用sqlserver储存过程返回多个结果集

    首先安装扩展 windows 分为两个步骤 找到对应自己PHP版本的pdo扩展,下载解压出来,并且在php.ini里面启用扩展,需要注意的问题是php版本以及是否为安全版本 下载 ODBC Drive ...

  6. 四十三、在SAP中初始化勾选值

    一.上代码 二.运行时,勾选框会被自动勾选中 三.表单如下

  7. Swift 类的使用class

    /* 类属性的介绍 Swift中类的属性有多种 1.存储属性:存储示例的常量和变量 2.计算属性:通过某种方式计算出来的属性 3.类属性:与整个类自身相关的属性 存储属性 存储属性是最简单的属性,它作 ...

  8. 事件时间(event time)与水印(watermark)

    事件时间和水印诞生的背景 在实际的流式计算中数据到来的顺序对计算结果的正确性有至关重要的影响 比如:某数据源中的某些数据由于某种原因(如:网络原因,外部存储自身原因)会有2秒的延时,也就是在实际时间的 ...

  9. MESI缓存一致性协议

    整理一下一些计算机的基础概念. 概念 MESI(Modified, Exclusive, Shared, Invalid) 也称 Illinois 协议, 由美帝UIUC(University of ...

  10. 十三、react-router 4.x的基本配置

    路由的定义及作用 根组件根据客户端不同的请求网址显示时,要卸载上一个组件,再挂载下一个组件,如果手动操作话将是一个巨大麻烦.具体过程如下图: [根组件] ↑ [首页组件] [新闻组件] [商品组件] ...