[最短路 杂题] BZOJ 4356 Ceoi2014 Wall

具体看题解 我说不清楚
首先可以证明 这个环必然包裹住了所有左上角到其他城市的最短路
这里写图片描述
证明可以调整为包进去 而不会边劣
然后求出所有最短路 然后把它们包进去的话 把一个交点拆成四个点 然后跑一下左上角绕一圈到左上角的最短路

这里写图片描述

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<queue>
#define cl(x) memset(x,0,sizeof(x))
using namespace std;
typedef long long ll;
typedef pair<ll,int> abcd;

inline char nc(){
  static char buf[100000],*p1=buf,*p2=buf;
  return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline void read(int &x){
  char c=nc(),b=1;
  for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
  for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}

const int N=402*402*4+5;
const int M=N*4;
struct edge{
  int u,v,w,next;
}G[M];
int head[N],inum;
inline void add(int u,int v,int w,int p){
  G[p].u=u; G[p].v=v; G[p].w=w; G[p].next=head[u]; head[u]=p;
}
inline void link(int u,int v,int w){
  add(u,v,w,++inum); add(v,u,w,++inum);
}
#define V G[p].v

const int _N=405;

int n,m;
int a[_N][_N],b[_N][_N],c[_N][_N];
int tot;

ll dis[N]; int pre[N];
priority_queue<abcd,vector<abcd>,greater<abcd> > Q;

inline void Dij(int S){
  for (int i=1;i<=tot;i++) dis[i]=1LL<<60,pre[i]=0;
  dis[S]=0; Q.push(abcd(0,S));
  while (!Q.empty()){
    abcd t=Q.top(); Q.pop();
    int u=t.second;
    if (dis[u]!=t.first) continue;
    for (int p=head[u];p;p=G[p].next)
      if (dis[V]>dis[u]+G[p].w)
    pre[V]=u,Q.push(abcd(dis[V]=dis[u]+G[p].w,V));
  }
}

#define P(x,y) ((m+1)*((x)-1)+(y))
#define PP(x,y,z) ((P(x,y)-1)*4+z+1)

int vst[N];
int mark[N][4],del[N];
inline void Link(int u,int v,int w){
  if (del[u] || del[v]) return;
  link(u,v,w);
}

inline void dfs(int u){
  if (u==1 || vst[u]) return;
  vst[u]=1;
  if (pre[u]==u-1) mark[u][3]=mark[pre[u]][1]=1;
  if (pre[u]==u+1) mark[u][1]=mark[pre[u]][3]=1;
  if (pre[u]==u-m-1) mark[u][0]=mark[pre[u]][2]=1;
  if (pre[u]==u+m+1) mark[u][2]=mark[pre[u]][0]=1;
  dfs(pre[u]);
}

int main(){
  freopen("t.in","r",stdin);
  freopen("t.out","w",stdout);
  read(n); read(m);
  tot=(n+1)*(m+1);
  for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) read(a[i][j]);
  for (int i=1;i<=n;i++) for (int j=1;j<=m+1;j++) read(b[i][j]),link(P(i,j),P(i+1,j),b[i][j]);
  for (int i=1;i<=n+1;i++) for (int j=1;j<=m;j++) read(c[i][j]),link(P(i,j),P(i,j+1),c[i][j]);
  Dij(1);
  for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) if (a[i][j]) dfs(P(i,j));
  cl(head); inum=0;
  for (int i=1;i<=n;i++)
    for (int j=1;j<=m;j++)
      if (a[i][j])
    del[PP(i,j,2)]=del[PP(i+1,j,1)]=del[PP(i,j+1,3)]=del[PP(i+1,j+1,0)]=1;
  del[1]=1;
  for (int i=1;i<=n+1;i++)
    for (int j=1;j<=m+1;j++)
      for (int k=0;k<4;k++)
    if (!mark[P(i,j)][k])
      Link(PP(i,j,k),PP(i,j,(k+1)%4),0);
  for (int i=1;i<=n;i++)
    for (int j=1;j<=m+1;j++)
      Link(PP(i,j,3),PP(i+1,j,0),b[i][j]),Link(PP(i,j,2),PP(i+1,j,1),b[i][j]);
  for (int i=1;i<=n+1;i++)
    for (int j=1;j<=m;j++)
      Link(PP(i,j,1),PP(i,j+1,0),c[i][j]),Link(PP(i,j,2),PP(i,j+1,3),c[i][j]);
  tot<<=2; Dij(2);
  printf("%lld\n",dis[4]);
  /*int t=4;
    while (t) printf("%d\n",t),t=pre[t];*/
  return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值