…
「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篇题解,有不好的地方请多多见谅(/▽\)