「USACO24OPEN Bronze」Walking Along a Fence题解


「USACO24OPEN Bronze」Walking Along a Fence题解

蒟蒻没咋写过题解如果不好请见谅(合十)在这里插入图片描述
读题发现是在一个区间内进行计数,所以说这道题拿前缀和来写会比较好
但是我们再仔细读题,发现它不同于普通的前缀和,他是一个二维的有4个方向的前缀和
所以我们可以尝试建立一个二维数组来对于前缀和进行存储。
ok基本思路有了就是二维的前缀和那就接下来一步步实现

一.常规输入
输入时把各个栅栏的横纵坐标进行存储,奶牛的目的地直接输入求前缀和就可

int n,p,x[200005],y[200005],dp[1005][1005],xx,x2,yyy,y2;
/* 114514字符内容*/
for(int i=1;i<=p;i++) cin>>x[i]>>y[i];
/* 114514字符内容*/
for(int i=1;i<=n;i++)
		cin>>xx>>yyy>>x2>>y2;

二.前缀和
ok又要来理思路了
对于一般的前缀和,我们都只是在一个一维数组上进行的,那我们怎么把一个二维的闭环变成一维呢?
很显然
拉直

那怎么拉呢?
在这里插入图片描述
对于一个二维且每个顶点都是90度的闭环
一个篱笆延向另一个顶点只可能在4个方向上(x↑,x↓,y←,y→),所以我们只需要打上标记,让每个篱笆上面的点指向下一个篱笆的方向然后再前缀和+1,就是我们这道题的思路。

很简单,我们可以写出代码:

if(x[i]==x[i+1]){//y方向上前缀和
		if(y[i]<y[i+1]) for(int j=y[i]+1;j<=y[i+1];j++) dp[x[i]][j]=dp[x[i]][j-1]+1;//上
		else			for(int j=y[i]-1;j>=y[i+1];j--) dp[x[i]][j]=dp[x[i]][j+1]+1;//下
	}
	else{//x 方向上前缀和
		if(x[i]<x[i+1]) for(int j=x[i]+1;j<=x[i+1];j++) dp[j][y[i]]=dp[j-1][y[i]]+1;//l 
		else			for(int j=x[i]-1;j>=x[i+1];j--) dp[j][y[i]]=dp[j+1][y[i]]+1;//r 
	}

但是因为这是一个环.所以我们要在结点处进行特判:

if(i==p){
		if(x[p]==x[1]){//结点特判
			if(y[p]<y[1]) for(int j=y[p]+1;j<=y[1];j++) dp[x[p]][j]=dp[x[p]][j-1]+1;
			else		  for(int j=y[p]-1;j>=y[1];j--) dp[x[p]][j]=dp[x[p]][j+1]+1;
		}
		else{
			if(x[p]<x[1]) for(int j=x[p]+1;j<=x[1];j++) dp[j][y[p]]=dp[j-1][y[p]]+1;
			else 		  for(int j=x[p]-1;j>=x[1];j--) dp[j][y[p]]=dp[j+1][y[p]]+1;
		}
	}

三.求长度
长度简单,前缀和即可。
但是因为是在一个环上,所以会有两条路径,可就那咋办??
因为是前缀和,所以总路程就是最后特判的值dp[x[1][y[1],用这个值减去当前求得第一个路径就能得第二个,取最小值
代码:

cnt=dp[x[1]][y[1]];//总长 
for(int i=1;i<=n;i++){
	cin>>xx>>yyy>>x2>>y2;
	int ans1=abs(dp[xx][yyy]-dp[x2][y2]),ans2=cnt-ans1;
	cout<<min(ans1,ans2)<<endl;

四.代码
ok那么所有框架已经写出来了搓一起就行了。
代码:

#include<bits/stdc++.h>
using namespace std;
int n,p,x[200005],y[200005],dp[1005][1005],cnt,xx,x2,yyy,y2;
int main(){
	cin>>n>>p;
	for(int i=1;i<=p;i++) cin>>x[i]>>y[i];
	for(int i=1;i<=p;i++){
		if(i==p){
			if(x[p]==x[1]){//结点特判 																																																																																																																																																																																																																																																																																												//你在找什么 
				if(y[p]<y[1]) for(int j=y[p]+1;j<=y[1];j++) dp[x[p]][j]=dp[x[p]][j-1]+1;
				else		  for(int j=y[p]-1;j>=y[1];j--) dp[x[p]][j]=dp[x[p]][j+1]+1;
			}
			else{
				if(x[p]<x[1]) for(int j=x[p]+1;j<=x[1];j++) dp[j][y[p]]=dp[j-1][y[p]]+1;
				else 		  for(int j=x[p]-1;j>=x[1];j--) dp[j][y[p]]=dp[j+1][y[p]]+1;
			}
		}
		if(x[i]==x[i+1]){//y方向上前缀和
			if(y[i]<y[i+1]) for(int j=y[i]+1;j<=y[i+1];j++) dp[x[i]][j]=dp[x[i]][j-1]+1;//上
			else			for(int j=y[i]-1;j>=y[i+1];j--) dp[x[i]][j]=dp[x[i]][j+1]+1;//下
		}
		else{//x 方向上前缀和
			if(x[i]<x[i+1]) for(int j=x[i]+1;j<=x[i+1];j++) dp[j][y[i]]=dp[j-1][y[i]]+1;//l 
			else			for(int j=x[i]-1;j>=x[i+1];j--) dp[j][y[i]]=dp[j+1][y[i]]+1;//r 
		}
	}
	
	cnt=dp[x[1]][y[1]];//总长 
	for(int i=1;i<=n;i++){
		cin>>xx>>yyy>>x2>>y2;
		int ans1=abs(dp[xx][yyy]-dp[x2][y2]),ans2=cnt-ans1;
		cout<<min(ans1,ans2)<<endl;
	}
}

这是这只蒟蒻的第3篇题解,有不好的地方请多多见谅(/▽\)

  • 12
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值