狼抓兔子

狼抓兔子

思路

将面看成点,然后将边转换成面和面之间的边,然后跑一遍最短路,就可以了。
但是具体那个是起点,那个是终点,是这么进行确定的,我还不太确定。

代码

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int M=3e6+5;
using pii=pair<int,int>;

int n,m;
int h[M],ne[M<<1],e[M<<1],w[M<<1],tot=1;
void add(int from,int to,int w1,int w2) {
    e[++tot]=to;  w[tot]=w1;  ne[tot]=h[from];  h[from]=tot;
    e[++tot]=from;w[tot]=w2;  ne[tot]=h[to];    h[to]=tot;
}

int dis[M];
bool vis[M];
int S=M-2,T=M-1;
int dij() {
    memset(dis,0x7f,sizeof(dis));
    dis[S]=0;
    priority_queue<pii>q;
    q.push({0,S});
    while(!q.empty()) {
        int now=q.top().second;
        q.pop();
        if(vis[now])continue;
        vis[now]=1;
        if(now==T)return dis[now];
        for(int i=h[now];i;i=ne[i]) {
            int to=e[i];
            if(dis[to]>dis[now]+w[i])
                dis[to]=dis[now]+w[i],q.push({-dis[to],to});
        }
    }
    return -1;
}

int id(int x,int y) {
    return (x-1)*(m-1)+y;
}

signed main() {
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    cin>>n>>m;
    for(int i=1;i<=n;i++)
        for(int j=1;j<m;j++) {
            int wi,x,y;cin>>wi;
            if(i==1)x=S,y=j;
            else if(i==n)x=T,y=id(2*(i-1),j);
            else x=id(2*i-1,j),y=id(2*i-2,j);
            add(x,y,wi,wi);
        }
    for(int i=1;i<n;i++)
        for(int j=1;j<=m;j++) {
            int wi,x,y;cin>>wi;
            if(j==1)x=T,y=id(2*i,j);
            else if(j==m)x=S,y=id(2*i-1,j-1);
            else x=id(2*i-1,j-1),y=id(2*i,j);
            add(x,y,wi,wi);
        }
    for(int i=1;i<n;i++)
        for(int j=1;j<m;j++) {
            int wi;cin>>wi;
            int x=id(2*i,j),y=id(2*i-1,j);
            add(x,y,wi,wi);
        }
    cout<<dij();
    return 0;
}
posted @ 2022-12-19 18:49  basicecho  阅读(29)  评论(0)    收藏  举报