懒人终于开始写博客啦!~~~撒花~~~
这两天集中做了一下历届noip的搜索,还是很有收获的,所以整理成一篇文章。自认为是按照难度从小到大做的QWQ
1565: NOIP2004 虫食算
时间限制: 1 Sec 内存限制: 128 MB提交: 18 解决: 5
题目描述
输入
输出
样例输入
5
ABCED
BDACE
EBBAA
样例输出
1 0 3 4 2
提示
这个时候我好像还没有写过任何爆搜....于是当时我的思路是这样的: 考虑进位!要剪枝!没了
于是冷静下来整理出这样几个主要的点 首先剪枝【以下所有的东西都要考虑进位】1.如果我们搜到某一位 三个数都搜到了但是出现矛盾剪枝 2.某一位已经搜到了两个数 但是所有有能对的第三个数已经被占用 剪枝 然后就没有了。。。高能预警:前方有长代码
其实就是我不会写搜索。。。于是我讨论了每个数是否出现的情况。。。算了上代码
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
int n,ci[30],di[30],fi[30],pos[30],cnt;
char ch[30];
bool use[30],v[30];
bool check()
{
for(int i=0;i<n;i++)
if(v[fi[i]]&&v[ci[i]]&&v[di[i]])
{
int t=pos[ci[i]]+pos[di[i]];
if((t%n)!=pos[fi[i]]&&(t+1)%n!=pos[fi[i]]) return false;
}
else if((v[ci[i]]&&v[fi[i]])||(v[di[i]]&&v[fi[i]]))
{
int t;
if(v[ci[i]]&&v[fi[i]]) t=(pos[fi[i]]+n-pos[ci[i]])%n;
else t=(pos[fi[i]]+n-pos[di[i]])%n;
if(use[t]&&use[(t-1+n)%n]) return false;
}
else if(v[ci[i]]&&v[di[i]])
{
int t;
t=(pos[ci[i]]+pos[di[i]])%n;
if(use[t]&&use[(t+1)%n]) return false;
}
return true;
}
void print()
{
for(int i=1;i<n;i++) cout<<pos[i]<<" ";
cout<<pos[n];
cout<<endl;
}
void dfs(int x,int lef)
{
if(x==-1)
{
if(!check()) return;
print(); exit(0);
}
else
{
int r;
if(!check()) return;
if(v[ci[x]]&&v[di[x]])
{
int t=(pos[ci[x]]+pos[di[x]]+lef)%n;
if(v[fi[x]])
{
if(t!=pos[fi[x]]||use[t]&&pos[fi[x]]!=t) return ;
if(pos[ci[x]]+pos[di[x]]+lef>=n) r=1;
else r=0;
dfs(x-1,r);
}
else
{
if(use[t]) return ;
use[t]=1;
pos[fi[x]]=t;
if(pos[ci[x]]+pos[di[x]]+lef>=n) r=1;
else r=0;
v[fi[x]]=1;
dfs(x-1,r);
v[fi[x]]=0;
use[t]=0;
}
}
else if(v[ci[x]])
{
if(v[fi[x]])
{
int t=(pos[fi[x]]+n-pos[ci[x]]-lef)%n;
if(use[t]) return ;
else
{
use[t]=1;
pos[di[x]]=t;
if(pos[ci[x]]+pos[di[x]]>pos[fi[x]]) r=1;
else r=0;
v[di[x]]=1;
dfs(x-1,r);
v[di[x]]=0;
use[t]=0;
}
}
else
{
for(int i=n-1;i>=0;i--)
if(!use[i])
{
int t=(pos[ci[x]]+i+lef)%n;
if(use[t]&&t!=i) continue;
use[i]=1;
use[t]=1;
pos[di[x]]=i; pos[fi[x]]=t;
if(pos[ci[x]]+pos[di[x]]+lef>=n) r=1;
else r=0;
v[di[x]]=1; v[fi[x]]=1;
dfs(x-1,r);
use[i]=0;
v[di[x]]=0; v[fi[x]]=0; use[t]=0;
}
}
}
else if(v[di[x]])
{
if(v[fi[x]])
{
int t=(pos[fi[x]]+n-pos[di[x]]-lef)%n;
if(use[t]) return ;
else
{
use[t]=1;
pos[ci[x]]=t;
if(pos[ci[x]]+pos[di[x]]>pos[fi[x]]) r=1;
else r=0;
v[ci[x]]=1;
dfs(x-1,r);
use[t]=0;
v[ci[x]]=0;
}
}
else
{
for(int i=n-1;i>=0;i--)
if(!use[i])
{
pos[ci[x]]=i;
int t=(pos[ci[x]]+pos[di[x]]+lef)%n;
pos[fi[x]]=t;
if(use[t]&&t!=i) continue;
use[i]=1; use[t]=1;
if(pos[ci[x]]+pos[di[x]]+lef>=n) r=1;
else r=0;
v[ci[x]]=1; v[fi[x]]=1;
dfs(x-1,r);
use[i]=0; use[t]=0;
v[ci[x]]=0; v[fi[x]]=0;
}
}
}
else
{
for(int i=n-1;i>=0;i--)
{
if(!use[i])
{
pos[ci[x]]=i;
use[i]=1;
v[ci[x]]=1;
for(int j=n-1;j>=0;j--)
if(!use[j]||(use[j]&&di[x]==ci[x]))
{
pos[di[x]]=j;
use[j]=1;
v[di[x]]=1;
int t=(pos[ci[x]]+pos[di[x]]+lef)%n;
if(v[fi[x]])
{
if(t!=pos[fi[x]]) {use[j]=0; v[di[x]]=0; continue ;}
if(pos[ci[x]]+pos[di[x]]+lef>=n) r=1;
else r=0;
dfs(x-1,r);
}
else
{
if(use[t]&&j!=t) {use[j]=0; v[di[x]]=0; continue ;}
else if(j!=t||(j==t&&fi[x]==di[x]))
{
pos[fi[x]]=(t%n);
use[t]=1;
if(pos[ci[x]]+pos[di[x]]+lef>=n) r=1;
else r=0;
v[fi[x]]=1;
dfs(x-1,r);
v[fi[x]]=0;
use[t]=0;
}
}
use[j]=0;
v[di[x]]=0;
}
use[i]=0;
v[ci[x]]=0;
}
}
}
}
}
int main()
{
cin>>n;
scanf("%s",ch);
for(int i=0;i<n;i++) ci[i]=ch[i]-'A'+1;
scanf("%s",ch);
for(int i=0;i<n;i++) di[i]=ch[i]-'A'+1;
scanf("%s",ch);
for(int i=0;i<n;i++) fi[i]=ch[i]-'A'+1;
dfs(n-1,0);
return 0;
}
为什么觉得这个优快云的格式看着这么丑呢QAQ 【我就不说我代码写得丑】
1620: NOIP2011 Mayan游戏
时间限制: 5 Sec 内存限制: 128 MB提交: 28 解决: 5
题目描述
Mayan puzzle 是最近流行起来的一个游戏。游戏界面是一个 7行 5 列的棋盘,上面堆放着一些方块,方块不能悬空堆放,即方块必须放在最下面一行,或者放在其他方块之上。游戏通关是指在规定的步数内消除所有的方块,消除方块的规则如下:
1、 每步移动可以且仅可以沿横向(即向左或向右)拖动某一方块一格:当拖动这一方块时,如果拖动后到达的位置(以下称目标位置)也有方块,那么这两个方块将交换位置(参见输入输出样例说明中的图 6 到图 7);如果目标位置上没有方块,那么被拖动的方块将从原来的竖列中抽出,并从目标位置上掉落(直到不悬空,参见下面图 1 和图2);
2、 任一时刻,如果在一横行或者竖列上有连续三个或者三个以上相同颜色的方块,则它们将立即被消除(参见图 1 到图3)。
注意:
a) 如果同时有多组方块满足消除条件,几组方块会同时被消除(例如下面图 4,三个颜色为 1 的方块和三个颜色为 2 的方块会同时被消除,最后剩下一个颜色为 2 的方块)。
b) 当出现行和列都满足消除条件且行列共享某个方块时,行和列上满足消除条件的所有方块会被同时消除(例如下面图 5 所示的情形,5 个方块会同时被消除)。
3、 方块消除之后,消除位置之上的方块将掉落,掉落后可能会引起新的方块消除。注意:掉落的过程中将不会有方块的消除。
上面图 1 到图 3 给出了在棋盘上移动一块方块之后棋盘的变化。棋盘的左下角方块的坐标为(0, 0),将位于(3, 3)的方块向左移动之后,游戏界面从图 1 变成图 2 所示的状态,
此时在一竖列上有连续三块颜色为 4 的方块,满足消除条件,消除连续 3块颜色为 4的方块后,上方的颜色为 3 的方块掉落,形成图 3 所示的局面。
输入
输入文件共 6行。
第一行有一个整数n,表示要求游戏通关的步数。
接下来的 5行,描述 7*5 的游戏界面。每行若干个整数,每两个整数之间用一个空格隔开,每行以一个 0 结束,自下向上表示每竖列方块的颜色编号(颜色不多于 10 种,从 1 开始顺序编号,相同数字表示相同颜色)。
输入数据保证初始棋盘中没有可以消除的方块。
输出
如果有解决方案,输出 n 行,每行包含 3 个整数x,y,g,表示一次移动,每两个整数之间用一个空格隔开,其中(x,y)表示要移动的方块的坐标,g 表示移动的方向,1 表示向右移动,-1 表示向左移动。注意:多组解时,按照 x 为第一关健字,y 为第二关键字,1优先于-1,给出一组字典序最小的解。游戏界面左下角的坐标为(0,0)。
如果没有解决方案,输出一行,包含一个整数-1。
这个搜索我写的真的是很差。。。跑了4s多
这个主要的剪枝:
1.如果两个相邻位置都是方块 我们只交换一次
2.如果两个方块颜色一样 我们不交换
3.如果某个颜色的剩余少于3个 可以剪枝
然后我调了好久啊 我们真的要好好看题 如果在一横行或者竖列上有连续三个或者三个以上相同颜色的方块,则它们将立即被消除
我就是没有注意这个 以为只要三个联通就可以消除 然后WAWAWAWAWAWAWAWA
高能预警:前方有长代码
好了这个自认为写得不怎么样QAQ
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
int mp[8][8],n,colnum,num[11];
int lst[8][8][6],col[11][8];
int xx[10],yy[10],s[10];
bool ins(int x,int y){return x>0&&x<=7&&y>0&&y<=5;}
bool check(int x,int y,int dep)
{
if(!ins(x,y)||!ins(x,y+1)) return false;
return (lst[x][y][dep]&&!lst[x][y+1][dep]||lst[x][y][dep]!=lst[x][y+1][dep]&&lst[x][y][dep]);
}
bool check2(int x,int y,int dep)
{
return (lst[x][y][dep]&&!lst[x][y-1][dep]&&ins(x,y)&&ins(x,y-1));
}
int cal(int dep)
{
int minn=100;
for(int i=1;i<=colnum;i++)
if(col[i][dep]) minn=min(minn,col[i][dep]);
return minn;
}
int sx[40],sy[40],h,t;
int wx[5]={0,0,1,-1},wy[5]={1,-1,0,0};
int v[10][10],T;
bool hang,lie,xiao[8][6];
bool ok(int x,int y)
{
hang=0,lie=0;
T++;
int c=mp[x][y];
if(c==0) return false;
h=t=0;
sx[++t]=x; sy[t]=y;
v[x][y]=T;
while(h!=t)
{
int nx=sx[++h],ny=sy[h];
for(int i=0;i<2;i++)
{
int dx=nx+wx[i],dy=ny+wy[i];
if(!ins(dx,dy)||mp[dx][dy]!=c||v[dx][dy]==T) continue;
sx[++t]=dx,sy[t]=dy,v[dx][dy]=T;
}
if(h>=3) return 1;
}
T++;
h=t=0;
sx[++t]=x; sy[t]=y;
v[x][y]=T;
while(h!=t)
{
int nx=sx[++h],ny=sy[h];
for(int i=2;i<4;i++)
{
int dx=nx+wx[i],dy=ny+wy[i];
if(!ins(dx,dy)||mp[dx][dy]!=c||v[dx][dy]==T) continue;
sx[++t]=dx,sy[t]=dy,v[dx][dy]=T;
}
if(h>=3) return 1;
}
return false;
}
void fill()
{
for(int i=1;i<=7;i++)
for(int j=1;j<=5;j++)
if(xiao[i][j])
{
num[mp[i][j]]--;
mp[i][j]=0;
}
}
bool xc()
{
bool flag=0;
memset(xiao,0,sizeof xiao);
for(int i=1;i<=7;i++)
for(int j=1;j<=5;j++)
if(ok(i,j)) flag=1,xiao[i][j]=1;
if(flag) fill();
return flag;
}
void falling()
{
for(int j=1;j<=5;j++)
{
for(int i=1;i<=7;i++)
if(!mp[i][j])
{
int p=0;
while(!mp[i+p][j]&&p+i<=7) p++;
for(int l=i;l+p<=7;l++)
mp[l][j]=mp[l+p][j],mp[l+p][j]=0;
}
}
}
int numa=0;
void mov(int x,int y,int dep,int o)
{
xx[dep]=x; yy[dep]=y;
for(int i=1;i<=7;i++)
for(int j=1;j<=5;j++)
mp[i][j]=lst[i][j][dep];
for(int i=1;i<=colnum;i++)
num[i]=col[i][dep];
if(o==0) swap(mp[x][y],mp[x][y+1]);
else swap(mp[x][y],mp[x][y-1]);
falling();
while(xc()) falling();
for(int i=1;i<=7;i++)
for(int j=1;j<=5;j++)
lst[i][j][dep+1]=mp[i][j];
for(int i=1;i<=colnum;i++)
col[i][dep+1]=num[i];
}
bool pty()
{
for(int i=1;i<=colnum;i++)
if(num[i]) return false;
return true;
}
void print()
{
for(int i=0;i<n;i++)
cout<<yy[i]-1<<" "<<xx[i]-1<<" "<<s[i]<<endl;
}
int cnt=0;
void dfs(int stp)
{
if(stp==n)
{
if(pty()) {print(); exit(0);}
return ;
}
else
{
if(cal(stp)<3) return;
for(int j=1;j<=5;j++)
for(int i=1;i<=7;i++)
{
if(check(i,j,stp))
{
s[stp]=1;
mov(i,j,stp,0);
dfs(stp+1);
}
if(check2(i,j,stp))
{
s[stp]=-1;
mov(i,j,stp,1);
dfs(stp+1);
}
}
}
}
int main()
{
scanf("%d",&n);
int a,cnt;
for(int i=1;i<=5;i++)
{
cnt=0;
while(~scanf("%d",&a)&&a)
mp[++cnt][i]=a,colnum=max(colnum,a),num[a]++;
}
for(int i=1;i<=7;i++)
for(int j=1;j<=5;j++) lst[i][j][0]=mp[i][j];
for(int i=1;i<=colnum;i++) col[i][0]=num[i];
dfs(0);
printf("-1");
return 0;
}
1605: NOIP2009 靶形数独
时间限制: 2 Sec 内存限制: 128 MB提交: 11 解决: 4
题目描述


输入
输出
样例输入
7 0 0 9 0 0 0 0 1
1 0 0 0 0 5 9 0 0
0 0 0 2 0 0 0 8 0
0 0 5 0 2 0 0 0 3
0 0 0 0 0 0 6 4 8
4 1 3 0 0 0 0 0 0
0 0 7 0 0 2 0 9 0
2 0 1 0 6 0 8 0 4
0 8 0 5 0 4 0 1 2
样例输出
2829
提示
这个。。。不好意思我搜题解了。。。因为最开始加了一个弱弱的剪枝然后就next_permutation 样例跑了15s...所以我就义无反顾的。。。搜了题解【请忽略博主的语文水平】
然后我发现位运算这个东西真是非常巧妙啊!O(∩_∩)O
首先我们在输入之后排序 从缺数少的行先搜 这样应该会更优一点(...)
然后我们记录三个数组分别表示 每行 每列 每个3*3格子的数字使用情况 位运算好啊 妙不可言啊 所以上代码吧
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
int score[10][10]=
{
0,0,0,0,0,0,0,0,0,0,
0,6,6,6,6,6,6,6,6,6,
0,6,7,7,7,7,7,7,7,6,
0,6,7,8,8,8,8,8,7,6,
0,6,7,8,9,9,9,8,7,6,
0,6,7,8,9,10,9,8,7,6,
0,6,7,8,9,9,9,8,7,6,
0,6,7,8,8,8,8,8,7,6,
0,6,7,7,7,7,7,7,7,6,
0,6,6,6,6,6,6,6,6,6,
} ;
int mp[10][10],z[10],h[110],e[3][3],k[10],st[10],num[10],ans;
int cal()
{
int res=0;
for(int i=1;i<=9;i++)
for(int j=1;j<=9;j++)
res+=mp[i][j]*score[i][j];
return res;
}
void dfs(int x) // z[i]和h[j]
{
if(x==10)
{
ans=max(ans,cal());
return ;
}
else
{
int i,pos,p,j,xx,s;
i=st[x]; //表示当前搜索的行
pos=(1<<9)-1-k[i]; //表示当前行的空白列
p=pos&-pos; //表示第一个空白列
k[i]|=p; //把这位填上
j=(int)log2(p)+1; //缺少位的二进制表示
xx=(1<<9)-1-(z[i]|h[j]|e[(i-1)/3][(j-1)/3]);
while(xx>0)
{
s=xx&-xx;
xx-=s;
mp[i][j]=(int)log2(s)+1;
z[i]|=s;
h[j]|=s;
e[(i-1)/3][(j-1)/3]|=s;
if(pos==p) dfs(x+1);
else dfs(x);
z[i]-=s;
h[j]-=s;
e[(i-1)/3][(j-1)/3]-=s;
}
k[i]-=p;
}
}
int main()
{
for(int i=1;i<=9;i++)
for(int j=1;j<=9;j++)
{
scanf("%d",&mp[i][j]);
if(mp[i][j])
{
k[i]|=(1<<(j-1));
int p=(1<<(mp[i][j]-1));
if((p&z[i])||(p&h[j])||(p&e[(i-1)/3][(j-1)/3])) {cout<<-1; return 0;}
z[i]|=p;
h[j]|=p;
e[(i-1)/3][(j-1)/3]|=p;
}
else num[i]++;
}
for(int i=1;i<=9;i++) st[i]=i;
for(int i=1;i<=9;i++)
for(int j=i+1;j<=9;j++)
if(num[st[i]]>num[st[j]]) swap(st[i],st[j]);
int p=1;
while(num[p]==0) p++;
dfs(p);
if(ans) cout<<ans;
else cout<<-1;
return 0;
}
这个时候我就有一点颓了。。。于是水了一个八数码【当然也没加什么估价函数】然后简单回忆了一下过去,,,
所以最后还是要鼓起勇气做华容道啊QWQ
1643: NOIP 2013 华容道
时间限制: 1 Sec 内存限制: 128 MB提交: 43 解决: 5
题目描述
输入
输出
样例输入
3 4 2
0 1 1 1
0 1 1 0
0 1 0 0
3 2 1 2 2 2
1 2 2 2 3 2
样例输出
2
-1
提示
必然是从位置(2, 2)上与当前图中目标位置上的棋子交换位置,之后能与空白块交换位置的只有当前图中目标位置上的那个棋子,因此目标棋子永远无法走到它的目标位置, 游戏无法完成。
这个ljss神犇第一次讲的时候我没有听懂...于是留下了非常恐怖的印象...
但是还是要鼓起勇气做呀!首先考虑60分做法 就是bfs!然后我们考虑优化 bfs的时间浪费在于一次又一次的搜这张图.所以我们可以想一想能不能提前跑出来。。。
不卖关子了 一个方块移动的条件是 周围有空格 所以列出状态move[i][j][k][l]表示 当前需要移动的块在(i,j),原来空白块在k方向,预计把空白块移动到j方向的最少步数
解释一下 这里方向表示空白块与当前块相邻 只有上下左右四个方向 然后这个数组我们可以bfs预处理出来 然后注意bfs的时候不能经过当前块
我们给每个位置设置四种状态dis[i][j][k]表示 当前需要移动的块在(i,j),空白块在其k方向的最小花费。然后我们可以先跑一边bfs确定把空白块移动到起始位置旁边的花费【这里我犯了一个刚写bfs都不会犯的错误导致无限RE】然后把四个状态扔进队列跑spfa
不要连边直接跑!不要连边直接跑!不要连边直接跑!为什么要给自己找麻烦呢
这好像是OI生涯最长代码?如果后来没删除加边还要多好多QAQ
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
# define inf 0x3f3f3f3f
using namespace std;
int f[5005],q[5005];
int n,m,qq,mp[32][32],mov[32][32][5][5];
int h,t,xx[1005],yy[1005],stp[32][32],wx[4]={-1,1,0,0},wy[4]={0,0,-1,1};
int ob[4]={1,0,3,2},sx,sy,tx,ty,kx,ky;
bool v[5005];
bool ins(int x,int y){return x>0&&x<=n&&y>0&&y<=m;}
void find(int a,int b)
{
mp[a][b]=0;
if(mp[a-1][b])
{
h=t=0;
memset(stp,0,sizeof stp);
xx[++t]=a-1,yy[t]=b;
while(h!=t)
{
int x=xx[++h],y=yy[h];
for(int i=0;i<4;i++)
{
int nx=x+wx[i],ny=y+wy[i];
if(!mp[nx][ny]||!ins(nx,ny)||stp[nx][ny]) continue;
xx[++t]=nx,yy[t]=ny,stp[nx][ny]=stp[x][y]+1;
}
}
if(stp[a+1][b]&&mp[a+1][b]&&ins(a+1,b)) mov[a][b][0][1]=stp[a+1][b];
if(stp[a][b+1]&&mp[a][b+1]&&ins(a,b+1)) mov[a][b][0][3]=stp[a][b+1];
if(stp[a][b-1]&&mp[a][b-1]&&ins(a,b-1)) mov[a][b][0][2]=stp[a][b-1];
}
if(mp[a+1][b])
{
h=t=0;
memset(stp,0,sizeof stp);
xx[++t]=a+1,yy[t]=b;
while(h!=t)
{
int x=xx[++h],y=yy[h];
for(int i=0;i<4;i++)
{
int nx=x+wx[i],ny=y+wy[i];
if(!mp[nx][ny]||!ins(nx,ny)||stp[nx][ny]) continue;
xx[++t]=nx,yy[t]=ny,stp[nx][ny]=stp[x][y]+1;
}
}
if(stp[a-1][b]&&mp[a-1][b]&&ins(a-1,b)) mov[a][b][1][0]=stp[a-1][b];
if(stp[a][b+1]&&mp[a][b+1]&&ins(a,b+1)) mov[a][b][1][3]=stp[a][b+1];
if(stp[a][b-1]&&mp[a][b-1]&&ins(a,b-1)) mov[a][b][1][2]=stp[a][b-1];
}
if(mp[a][b+1])
{
h=t=0;
memset(stp,0,sizeof stp);
xx[++t]=a,yy[t]=b+1;
while(h!=t)
{
int x=xx[++h],y=yy[h];
for(int i=0;i<4;i++)
{
int nx=x+wx[i],ny=y+wy[i];
if(!mp[nx][ny]||!ins(nx,ny)||stp[nx][ny]) continue;
xx[++t]=nx,yy[t]=ny,stp[nx][ny]=stp[x][y]+1;
}
}
if(stp[a+1][b]&&mp[a+1][b]&&ins(a+1,b)) mov[a][b][3][1]=stp[a+1][b];
if(stp[a-1][b]&&mp[a-1][b]&&ins(a-1,b)) mov[a][b][3][0]=stp[a-1][b];
if(stp[a][b-1]&&mp[a][b-1]&&ins(a,b-1)) mov[a][b][3][2]=stp[a][b-1];
}
if(mp[a][b-1])
{
h=t=0;
memset(stp,0,sizeof stp);
xx[++t]=a,yy[t]=b-1;
while(h!=t)
{
int x=xx[++h],y=yy[h];
for(int i=0;i<4;i++)
{
int nx=x+wx[i],ny=y+wy[i];
if(!mp[nx][ny]||!ins(nx,ny)||stp[nx][ny]) continue;
xx[++t]=nx,yy[t]=ny,stp[nx][ny]=stp[x][y]+1;
}
}
if(stp[a+1][b]&&mp[a+1][b]&&ins(a+1,b)) mov[a][b][2][1]=stp[a+1][b];
if(stp[a-1][b]&&mp[a-1][b]&&ins(a-1,b)) mov[a][b][2][0]=stp[a-1][b];
if(stp[a][b+1]&&mp[a][b+1]&&ins(a,b+1)) mov[a][b][2][3]=stp[a][b+1];
}
mp[a][b]=1;
}
int cal(int x,int y,int o) {return (x-1)*m+y+n*m*o;}
void bfs()
{
memset(stp,inf,sizeof stp);
h=t=0;
mp[kx][ky]=0;
mp[sx][sy]=0;
xx[++t]=kx,yy[t]=ky; stp[kx][ky]=0;
while(h!=t)
{
int x=xx[++h],y=yy[h];
for(int i=0;i<4;i++)
{
int nx=x+wx[i],ny=y+wy[i];
if(!ins(nx,ny)||!mp[nx][ny]||stp[nx][ny]<inf) continue;
xx[++t]=nx,yy[t]=ny,stp[nx][ny]=stp[x][y]+1;
}
}
mp[kx][ky]=1;
mp[sx][sy]=1;
if(stp[sx-1][sy]!=inf||(sx-1==kx&&sy==ky)) f[cal(sx,sy,0)]=stp[sx-1][sy];
if(stp[sx+1][sy]!=inf||(sx+1==kx&&sy==ky)) f[cal(sx,sy,1)]=stp[sx+1][sy];
if(stp[sx][sy-1]!=inf||(sx==kx&&sy-1==ky)) f[cal(sx,sy,2)]=stp[sx][sy-1];
if(stp[sx][sy+1]||(sx==kx&&sy+1==ky)) f[cal(sx,sy,3)]=stp[sx][sy+1];
}
int fr[5050];
void spfa()
{
h=t=0;
for(int i=0;i<4;i++)
{
int nx=sx+wx[i],ny=sy+wy[i];
if(ins(nx,ny)&&mp[nx][ny]&&stp[nx][ny]!=inf)
{
q[++t]=cal(sx,sy,i),v[cal(sx,sy,i)]=1,f[cal(sx,sy,i)]=stp[nx][ny];
}
}
while(h!=t)
{
int x=q[++h];
v[x]=false;
int i,j,now;
now=(x-1)/(n*m);
i=(x-now*(n*m))/m+1;
j=x-now*(n*m)-(i-1)*m;
int a=i+wx[now],b=j+wy[now];
if(h==5001) h=0;
if(f[cal(a,b,ob[now])]>f[x]+1&&ins(a,b))
{
f[cal(a,b,ob[now])]=f[x]+1;
if(!v[cal(a,b,ob[now])])
q[++t]=cal(a,b,ob[now]),v[cal(a,b,ob[now])]=1;
if(t==5001) t=0;
}
for(int l=0;l<4;l++)
if(l==now) continue;
else
{
int to=cal(i,j,l);
if(ins(i+wx[l],j+wy[l])&&mp[i+wx[l]][j+wy[l]]&&stp[i+wx[l]][j+wy[l]]<inf)
{
if(f[cal(i,j,l)]>f[x]+mov[i][j][now][l])
{
f[cal(i,j,l)]=f[x]+mov[i][j][now][l];
if(!v[cal(i,j,l)])
q[++t]=cal(i,j,l),v[cal(i,j,l)]=1;
if(t==5001) t=0;
}
}
}
}
}
int minn(int a,int b,int c,int d){return min(a,min(b,min(c,d)));}
void get_ans()
{
memset(f,0x3f,sizeof f);
memset(v,0,sizeof v);
bfs();
spfa();
int ans=minn(f[cal(tx,ty,0)],f[cal(tx,ty,1)],f[cal(tx,ty,2)],f[cal(tx,ty,3)]);
if(ans>=inf) ans=-1;
printf("%d\n",ans);
}
int main()
{
scanf("%d%d%d",&n,&m,&qq);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%d",&mp[i][j]);
memset(mov,0x3f,sizeof mov);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(mp[i][j]) find(i,j);
for(int i=1;i<=qq;i++)
{
scanf("%d%d%d%d%d%d",&kx,&ky,&sx,&sy,&tx,&ty);
if(sx==tx&&sy==ty) {printf("0\n"); continue;}
get_ans();
}
return 0;
}
于是我就这样把一周的青春送给了搜索【3天】完结撒花QWQ~~~