这个题我们把三个单位分开讨论
骑兵和步兵:由于一次超能力可以随便换任意次,容易想到对于一个步兵来说走到第 i i i 个点其使用超能力的次数应该是一个最短路问题,从 ( x 1 , y 1 ) (x_1,y_1) (x1,y1) 走到 ( x 2 , y 2 ) (x_2,y_2) (x2,y2) 若 h x 1 , y 1 < h x 2 , y 2 h_{x_1,y_1}<h_{x_2,y_2} hx1,y1<hx2,y2 则边权为 1 1 1(随便找个骑兵超能力一下),否则边权为 0 0 0。骑兵同理。
天兵:妥妥的工具人,由于对非超能力移动不做限制,天兵可以满图乱跑,跑到目标点再超能力一下把一个步兵或骑兵换过来,然后去下一个点。
然后就是,由于要求套路的二分答案超能力的次数,假如说第 i i i 个兵到 第 j j j 个目标点所用超能力次数大于二分的这个值就不用管(你也管不了不是),那么剩下的这些信息就是可以到的了,我们希望在不使用天兵的情况下尽可能多的让其它兵种上点,显然的我们跑一次二分图最大匹配即可(注意:一个目标点最多可以有 r i r_i ri 个兵在那里,遇到这种无法用常规方法处理的东西要拆点,我们把一个目标点拆成 r i r_i ri 个目标点再跑最大匹配,最短路的时候需要注意是跑原先的图,再用到第 i i i 个点的最短路去更新这拆出的 r i r_i ri 个点)。
然后剩下这些没匹配上的兵,我们只能用天兵去传送,这个时候点的限制就无意义了,天兵可以随便飞。这样我们使用超能力的次数为 2 k − a n s 2k-ans 2k−ans ( a n s ans ans 表示最大匹配数),再把这个值跟 m i d mid mid 比较即可。
代码(比较丑,仅供对拍)
#include<bits/stdc++.h>
using namespace std;
int n,m,k,t,s,vis[2005][2005],dis[2005][2005],h[505][505],d[2005][2005],tot;
int ssh(int x,int y){
return (x-1)*m+y;
}
vector<int>G[200];
struct troop{
int num,x,y;
}tp[206],re[206],R[206];
struct node{
int x,y;
};
struct qqq{
int y,next;
int used;
}a[5001],fc[500];
const int dx[]={
-1,1,0,0};
const int dy[]={
0,0,1,-1};
void BFS(int sx,int sy,bool M){
queue<node>q;
memset(vis,0,sizeof(vis));
memset(dis,0x3f,sizeof(dis));
dis[sx][sy]=0;
q.push((node){
sx,sy});
while(!q.empty()){
node top=q.front();
q.pop();
vis[top.x][top.y]=0;
for(int i=0;i<4;i++){
int ex=top.x+dx[i];
int ey=top.y+dy[i];
if(ex<1||ex>n||ey<1||ey>m)
continue;
int ds=0;
int tmp=((dis[top.x][top.y]&1)^M);
if(h[ex][ey]>h[top.x][top.y]&&tmp){
ds=1;
}
if((h[ex][ey]<h[top.x][top.y]&&!tmp)){
ds=1;
}
if(dis[top.x][top.y]+ds<dis[ex][ey]){
dis[ex][ey]=dis[top.x][top.y]+ds;
if(!vis[ex][ey]){
q.push((node){
ex,ey});
vis[ex][ey]=1;
}
}
}
}
}
int match[200],vs[200];
int dfs(int u){
for(int i=0;i<G[u].size();i++){
int y=G[u][i];
if(!vs[y]){
vs[y]=1;
if(!match[y]||dfs(match[y])){
match[y]=u;
return 1;
}
}
}
return 0;
}
bool check(int mid){
for(int i=0;i<=2*k;i++){
G[i].clear();
}
memset(match,0,sizeof(match));
for(int i=1;i<=2*k;i++){
for(int j=1;j<=tot;j++){
if(d[i][j]<=mid){
//add(i,j);
G[i].push_back(j);
}
}
}
int ans=0;
for(int i=1;i<=2*k;i++){
memset(vs,0,sizeof(vs));
ans+=dfs(i);
}
return ans+mid>=2*k;
}
int main()
{
ios::sync_with_stdio(0);
cin>>n>>m>>k>>t;
tot=0;
for(int i=1;i<=2*k+1;i++){
cin>>tp[i].x>>tp[i].y;
}
for(int i=1;i<=t;i++){
cin>>re[i].x>>re[i].y>>re[i].num;
while(re[i].num--){
R[++tot].x=re[i].x;
R[tot].y=re[i].y;
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>h[i][j];
}
}
for(int i=1;i<=2*k;i++){
BFS(tp[i].x,tp[i].y,i>k);
for(int j=1;j<=tot;j++){
d[i][j]=dis[R[j].x][R[j].y];
}
}
int L=0,rR=2*k;
while(L<rR){
int mid=(L+rR)/2;
if(check(mid))
rR=mid;
else
L=mid+1;
}
cout<<L<<endl;
return 0;
}