题解 [CTSC2002]玩具兵

这个题我们把三个单位分开讨论

骑兵和步兵:由于一次超能力可以随便换任意次,容易想到对于一个步兵来说走到第 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 2kans 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;
}

おすすめ

転載: blog.csdn.net/cryozwq/article/details/119150147