学到的东西:
1.用dis来记录从某起点到某一个点的最小步数,方便许多
2.用queue<sturct>q这样的形式来定义队列简单方便
3.数据范围的问题:INF最好用0X3F3F3F3F3F3F3F(七个3f)。因为:1.足够大,2.十个INF加起来不会爆longlong(这个地方让我改了五次,吐血,150个测试点跑半天)
4.一些小细节和技巧
输入输出样例
输入 #1
5 5 1 0 -1 0 1 -1 0 20 0 0 -1 -1 -1 -1 -1 -1 3 0 0 0 0 -1 0 0 0 0
输出 #1
14
一道思维题:只能用一次传送门。为什么呢?下面是证明:
如果用多次传送门xy -> pq ......mn ->rs ,不如直接xy ->rs,明显更划算。
但是可能有一次都不用传送门的情况,直接走到终点。所以就分两种情况考虑:用一次传送门或者用0次传送门(直接走过去)。然后就是一些小细节了,详情看代码。
Talk is cheap.Show me the code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f
#define endl '\n'
#define MOD 998244353
int n,m,w;
int a[2005][2005];
int dis[2005][2005];
int dx[]={1,-1,0,0};
int dy[]={0,0,1,-1};
int anss=INF;
int bfs(int sx,int sy){
memset(dis,-1,sizeof(dis));
dis[sx][sy]=0;
int ans=INF;
queue<pair<int,int>>q;
q.push({sx,sy});
while(!q.empty()){
int x=q.front().first,y=q.front().second;
q.pop();
for(int i=0;i<4;i++){
int xx=x+dx[i];
int yy=y+dy[i];
if(xx<1||xx>n||yy<1||yy>m||a[xx][yy]==-1||dis[xx][yy]!=-1) continue;
q.push({xx,yy});
dis[xx][yy]=dis[x][y]+1;
}
}
if(sx==1&&dis[n][m]!=-1) anss=min(anss,dis[n][m]*w);
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(a[i][j]>0&&dis[i][j]!=-1){
ans=min(ans,dis[i][j]*w+a[i][j]);
}
}
}
return ans;
}
void solve(){
cin>>n>>m>>w;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>a[i][j];
}
}
int ans1=bfs(1,1);
int ans2=bfs(n,m);
anss=min(anss,ans1+ans2);
if(anss>=INF) cout<<-1<<endl;
else cout<<anss<<endl;
}
signed main(){
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
solve();
}
//考虑边界了?
//考虑特殊情况?
//考虑输出中间值勘误?