牛客小白月赛75 D矩阵

牛客小白月赛75 D矩阵D 矩阵 牛客小白月赛 75 nowcoder com 思路 一个点有两种不同的状态 我们很容易想到分层图 对于分层图 有两种解法 一种是把所有边全部建好后去跑最短路 另一种就是在跑最短路的过程中加入一维状态去进行记录 对于第一种方法 难在建图

大家好,我是讯享网,很高兴认识大家。

D-矩阵_牛客小白月赛75 (nowcoder.com)


讯享网

思路:一个点有两种不同的状态,我们很容易想到分层图,对于分层图,有两种解法,一种是把所有边全部建好后去跑最短路,另一种就是在跑最短路的过程中加入一维状态去进行记录。对于第一种方法,难在建图,建完图后跑最短路的方式和原来无异,对于第二种方法,因为加入状态一栏,所以有点类似于dp状态转移的感觉,相比于第一种就难理解点。

法一:建完边再跑最短路:

建边思路:首先我们把这个图分为两层,对于我们走到点u,我们会对四个方向进行建边,而每一层的内部不会存在边,边只存在于层于层之间,对于点u,第0层会向第一层建一条边,而该边的边权取决于对应的点v是否在第一层,即a[v]是否为1,因为当a[v]为1时,我们可以直接走到该点,不需要对该点进行翻转,反之则边权为2,对于u的第二层也同理。

总上所述,我们需要2*n*m个点,还有一点就是对点进行编号,我们对第一层的点编号为1-n*m,对于第二层的点,我们在第一层对应的点编号上加上n*m即可,例如点u的第一层编号为x,那么第二层编号即为x+n*m。

#include <bits/stdc++.h> using namespace std; const int N = 2e6 + 5; typedef long long ll; const int maxv = 4e6 + 5; typedef pair<ll, ll> pll; int n, m; char a[1005][1005]; int get(int a,int b) { return (a-1)*m+b; } vector<pll> e[N]; void add(int u,int v,int w) { e[u].push_back({w,v}); } ll st[N],d[N]; int dx[]={0,0,1,-1}; int dy[]={1,-1,0,0}; void dijkstra(int c) { priority_queue<pll ,vector<pll>,greater<pll>> q; memset(d,0x3f,sizeof( d)); d[c]=0; q.push({0,c}); while(!q.empty()){ auto x=q.top(); q.pop(); int ver=x.second; int dis=x.first; if(st[ver]) continue; st[ver]=1; for(auto v: e[ver]){ int disn=v.first; int vern=v.second; if(d[vern]>d[ver]+disn){ d[vern]=d[ver]+disn; q.push({d[vern],vern}); } } } cout<<min(d[n*m],d[n*m*2])<<endl; } void solve() { cin>>n>>m; for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ cin>>a[i][j]; } } int t=n*m; for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ for(int k=0;k<4;k++){ int nx=dx[k]+i,ny=dy[k]+j; if(nx<1||nx>n||ny<1||ny>m) continue; int u,v; u=get(i,j),v=get(nx,ny)+t; if(a[nx][ny]=='1') add(u,v,1); else add(u,v,2); u=get(i,j)+t,v=get(nx,ny);; if(a[nx][ny]=='1') add(u,v,2); else add(u,v,1); } } } if(a[1][1]=='1') dijkstra(1+n*m); else dijkstra(1); } int main() { ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); int t = 1; //cin >> t; while (t--) { solve(); } system("pause"); return 0; }

讯享网

 法二:加入状态一维,对于这一维的状态,我们既可加到求最短路的数组d[N]中,又可在队列中加入这一变量,我们对所有的状态和1进行1异或即可。

对于队首所衍生点的状态是根据队首的状态进行确定的,例如111,第二个1的状态为0,因为队首的1^1=0,而对于第三个元素的状态,是根据第二个元素的状态进行判定,因为第二个元素状态为0,0^1=1,所以第三个元素的状态为1,依次类推。

讯享网#include<bits/stdc++.h> using namespace std; const int N=5e5+5; typedef long long ll; typedef pair<ll,ll> pll; int mod=1e9+7; const int maxv=4e6+5; int n,m; char a[1005][1005]; int dx[]={0,0,1,-1}; int dy[]={1,-1,0,0}; int d[1005][1005]; void solve() { cin>>n>>m; for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++) cin>>a[i][j]; } memset(d,0x3f,sizeof d); queue<array<int,3>> q; d[1][1]=0; q.push({1,1,a[1][1]-'0'}); while(!q.empty()){ auto [x,y,z]=q.front(); q.pop(); for(int i=0;i<4;i++){ int nx=dx[i]+x,ny=dy[i]+y; if(nx<1||nx>n||ny<1||ny>m) continue; int s=a[nx][ny]-'0'; if(s!=z){ if(d[nx][ny]>d[x][y]+1) { d[nx][ny]=d[x][y]+1; q.push({nx,ny,z^1}); } } else{ if(d[nx][ny]>d[x][y]+2){ d[nx][ny]=d[x][y]+2; q.push({nx,ny,z^1}); } } } } cout<<d[n][m]<<endl; } int main() { ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); int t; t=1; //cin>>t; while(t--){ solve(); } system("pause"); return 0; } 

小讯
上一篇 2025-01-10 11:14
下一篇 2025-03-15 20:53

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/48479.html