本题的难点是“移动过程中不能出现多颗棋子同时在某一格的情况”。

  事实上,可以忽略此条件,因为棋子是相同的,我们可以用合法的等效方案替代一棋子越过另一棋子的情况:A、B、C三格,A能在一步走到B,B也能在一步走到C。

在A的棋子需要走到存在棋子的B,接着走到C。此情形我们可以看成在B的棋子先走到C,接着在A的棋子走到B。

  BFS预处理出每个初始位置走到每个终止位置的最少步数。

  把初始位置抽象成二部图的左部,终止位置抽象成二部图的右部,左右之间边权为最少步数。

  那么次二部图的完备匹配对应着一种方案,匹配的边权和对应最少总步数。

  可用最佳匹配解决。

期望得分:

70(裸费用流)

90(n^4的KM算法)

100(n^3的KM算法)

//跑费用流,极限90(不会KM~~)

//by shenben
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<queue>
#define setfire(name) freopen(#name".in","r",stdin);freopen(#name".out","w",stdout);
using namespace std;
const int N=;
const int Z=;
const int inf=0x3f3f3f3f;
char mp[N][N];bool vis[N][N];int id[N][N];
int n,m,k,S,T,a,b,ans,f[Z][];
int dx[],dy[];
struct M{
int x,y,step;
M(int x=,int y=,int step=):x(x),y(y),step(step){}
};
struct edge{int v,next,cap,cost;}e[Z*Z*];int tot=,head[Z<<];bool mark[Z<<];
int dist[Z][Z],prev[Z<<],dis[Z<<],q[Z*];
inline int read(){
register int x=;register char ch=getchar();
while(ch<''||ch>''){ch=getchar();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}
return x;
}
inline void add(int x,int y,int z,int cost){
e[++tot].v=y;e[tot].cap=z;e[tot].cost=cost;e[tot].next=head[x];head[x]=tot;
e[++tot].v=x;e[tot].cap=;e[tot].cost=-cost;e[tot].next=head[y];head[y]=tot;
}
inline void init(){
n=read();m=read();k=read();a=read();b=read();
if(n==&&m==&&k==&&a==&&b==){puts("");exit();}
dx[]=a;dx[]=a;dx[]=-a;dx[]=-a;dx[]=b;dx[]=b;dx[]=-b;dx[]=-b;
dy[]=b;dy[]=-b;dy[]=b;dy[]=-b;dy[]=-a;dy[]=a;dy[]=a;dy[]=-a;
for(int i=;i<=n;i++) scanf("%s",mp[i]+);
for(int i=;i<=k;i++) f[i][]=read(),f[i][]=read();
for(int i=,x,y;i<=k;i++) x=read(),y=read(),id[x][y]=i;
}
inline bool inside(int x,int y){
return (x>&&x<=n&&y>&&y<=m);
}
inline void bfs(int num){
int cnt=,sx=f[num][],sy=f[num][];
memset(vis,,sizeof vis);
queue<M>q;q.push(M(sx,sy,));
if(id[sx][sy]){
dist[num][id[sx][sy]]=;
if(++cnt==k) return ;
}
while(q.size()){
M now=q.front();q.pop();
for(int i=,nx,ny;i<=;i++){
nx=now.x+dx[i];ny=now.y+dy[i];
if(vis[nx][ny]||!inside(nx,ny)||mp[nx][ny]=='*') continue;
vis[nx][ny]=;
if(id[nx][ny]){
if(dist[num][id[nx][ny]]==inf) dist[num][id[nx][ny]]=now.step+;
if(++cnt==k) return ;
}
q.push(M(nx,ny,now.step+));
}
}
}
inline void mapping(){
memset(dist,inf,sizeof dist);
S=;T=k<<|;
for(int i=;i<=k;i++){
bfs(i);
}
for(int i=;i<=k;i++){
for(int j=;j<=k;j++){
if(dist[i][j]!=inf) add(i,j+k,,dist[i][j]);
}
}
for(int i=;i<=k;i++) add(S,i,,),add(i+k,T,,);
}
/*稠密图EK不如zkw跑的快
inline bool spfa(){
for(int i=S;i<=T;i++) mark[i]=0,dis[i]=inf;
unsigned short h=0,t=1;q[t]=S;dis[S]=0;
while(h!=t){
int x=q[++h];mark[x]=0;
for(int i=head[x];i;i=e[i].next){
if(e[i].cap&&dis[e[i].v]>dis[x]+e[i].cost){
dis[e[i].v]=dis[x]+e[i].cost;
prev[e[i].v]=i;
if(!mark[e[i].v]){
mark[e[i].v]=1;
if(dis[e[i].v]<dis[x]) q[h--]=e[i].v;
else q[++t]=e[i].v;
}
}
}
}
return dis[T]!=inf;
}
inline void augment(){
int flow=inf;
for(int i=T;i!=S;i=e[prev[i]^1].v){
flow=min(flow,e[prev[i]].cap);
}
for(int i=T;i!=S;i=e[prev[i]^1].v){
e[prev[i]].cap-=flow;
e[prev[i]^1].cap+=flow;
}
ans+=flow*dis[T];
}*/
inline bool spfa(){
for(int i=S;i<=T;i++) mark[i]=,dis[i]=inf;
int h=,t=;q[t]=T;dis[T]=;mark[T]=;
while(h!=t){
int x=q[++h];mark[x]=;
for(int i=head[x];i;i=e[i].next){
int v=e[i].v;
if(e[i^].cap&&dis[v]>dis[x]+e[i^].cost){
dis[v]=dis[x]+e[i^].cost;
if(!mark[v]){
mark[v]=;
q[++t]=v;
}
}
}
}
return dis[S]<inf;
}
int dfs(int x,int f){
mark[x]=;
if(x==T) return f;
int used=,w;
for(int i=head[x];i;i=e[i].next){
int v=e[i].v;
if(!mark[v]&&e[i].cap&&dis[v]+e[i].cost==dis[x]){
w=dfs(v,min(f-used,e[i].cap));
e[i].cap-=w;e[i^].cap+=w;
ans+=w*e[i].cost;
used+=w;
if(used==f) return used;
}
}
return used;
}
inline void zkw(){
while(spfa()){
mark[T]=;
while(mark[T]){
memset(mark,,sizeof mark);
dfs(S,inf);
}
}
}
int main(){
setfire(chess);
init();
mapping();
zkw();
//while(spfa()) augment();
printf("%d",ans);
return ;
}
//最后一个点5.39s,zkw费用流死活跑不过去

SDOI2012 Round1 day2 象棋(chess)解题报告的更多相关文章

  1. SDOI2012 Round1 day2 拯救小云公主(dis)解题报告

    #include<cstdio> #include<cmath> #include<iostream> using namespace std; typedef l ...

  2. SDOI2012 Round1 day2 集合(set)解题报告

    //=====================以上为官方题解==============// 数据略水,暴力枚举50. 把边按照升序排一遍,在询问,水过. #include<cstdio> ...

  3. 洛谷 P4363 [九省联考2018]一双木棋chess 解题报告

    P4363 [九省联考2018]一双木棋chess 题目描述 菲菲和牛牛在一块\(n\)行\(m\)列的棋盘上下棋,菲菲执黑棋先手,牛牛执白棋后手. 棋局开始时,棋盘上没有任何棋子,两人轮流在格子上落 ...

  4. 洛谷 P2498 [SDOI2012]拯救小云公主 解题报告

    P2498 [SDOI2012]拯救小云公主 题目描述 英雄又即将踏上拯救公主的道路-- 这次的拯救目标是--爱和正义的小云公主. 英雄来到\(boss\)的洞穴门口,他一下子就懵了,因为面前不只是一 ...

  5. 雅礼集训 Day2 T3 联盟 解题报告

    联盟 题目描述 \(\text{G}\) 国周边的 \(n\) 个小国家构成一个联盟以抵御 \(\text{G}\) 国入侵, 为互相支援,他们建立了\(n−1\) 条双向通路, 使得任意两个国家可以 ...

  6. noip2013 Day2 T2 花匠 解题报告

    题目: 3289 花匠 2013年NOIP全国联赛提高组 时间限制: 1 s 空间限制: 128000 KB 题目描述 Description 花匠栋栋种了一排花,每株花都有自己的高度.花儿越长越大, ...

  7. 【百度之星2014~初赛(第二轮)解题报告】Chess

    声明 笔者近期意外的发现 笔者的个人站点http://tiankonguse.com/ 的非常多文章被其他站点转载.可是转载时未声明文章来源或參考自 http://tiankonguse.com/ 站 ...

  8. GX/GZOI2019 day2 解题报告

    GX/GZOI2019 day2 解题报告 题目链接 逼死强迫症 旅行者 旧词 t1 逼死强迫症 显然地,记 \(f(i)\) 为长度为 \(i\) 的木板的答案,可得: \(\\\) \[f(i)= ...

  9. 【NOIP2015】提高day2解题报告

    题目: P1981跳石头 描述 一年一度的“跳石头”比赛又要开始了!这项比赛将在一条笔直的河道中进行,河道中分布着一些巨大岩石.组委会已经选择好了两块岩石作为比赛起点和终点.在起点和终点之间,有 N ...

随机推荐

  1. python的模块itsdangerous

    这个模块主要用来签名和序列化 使用场景: 一.给字符串添加签名: 发送方和接收方拥有相同的密钥--"secret-key",发送方使用密钥对发送内容进行签名,接收方使用相同的密钥对 ...

  2. wireshark问题现象分析

    讲的非常透彻:建议学习 wireshark问题现象分析1:参考博客1 https://blog.csdn.net/u012398362/article/details/52276067 wiresha ...

  3. 面试题:如何在不使用临时变量temp的情况下交换两个整数的值?

    利用一个小技巧,一个整数a在异或另一个整数b两次以后所得的值还是整数a. 具体的过程我们可以自己找两个整数以二进制的形式自己在纸上画一下他们的异或过程.(异或的运算符号为"^") ...

  4. 智能选择器和语义化的CSS

    本文由白牙根据Heydon Pickering的<Semantic CSS With Intelligent Selectors>所译,整个译文带有我自己的理解与思想,如果译得不好或不对之 ...

  5. x^2 + (y-(x^2)(1/3))^2 = 1 心形方程 5.20无聊之作

    2017.05.20 一个无聊的周六,只能看别人秀恩爱.偶然间在网上看到一个有意思的方程 x^2 + (y-(x^2)(1/3))^2 = 1,据说这个方程可以绘制出一个爱心的形状.既然很无聊,就随便 ...

  6. vscode - 添加背景图片

    首先,Ctrl+Shift+P安装backround , 而后重启vscode会有默认的背景图片 修改背景图,可自定义三张 具体请看gif图 最开始时,发现png根本不是全透明,用ps处理了一下(下列 ...

  7. 最小化JavaScript代码

    1.去除不必要的格式符.空白符.凝视符. 这个操作.事实上能够理解为是一种格式化.尽管它操作的结果事实上是去除掉原始文件的那些格式. 2.模糊(Obfuscation)处理JAVASCRIP脚本源码. ...

  8. Java Swing界面编程(21)---事件处理:窗口事件

    WindowLIstener是专门处理窗口的事件监听窗口.一个窗口的全部变化.如窗口的打开.关闭等都能够使用这个接口进行监听. 实现WIndowListener: package com.beyole ...

  9. 【SpringMVC学习06】SpringMVC中的数据校验

    这一篇博文主要总结一下springmvc中对数据的校验.在实际中,通常使用较多是前端的校验,比如页面中js校验,对于安全要求较高的建议在服务端也要进行校验.服务端校验可以是在控制层conroller, ...

  10. nginx根据目录反向代理到后端服务器

    nginx根据目录反向代理到后端不同的服务器 server {         listen 80;         server_name demo.domain.com;         #通过访 ...