传送门:bzoj4356
题解
具体题解可以看这里
一开始读错题了,以为可以用多条环路来圈城市(不可做),实际上只能用一条从左上角出发并最终返回左上角的环路。
可以证明最优环路的一种可行解必然包含左上角点到每个城市左上角点的最短路径,所以先从左上角点出发跑出关于所有城市点的最短路DAG。
考虑把每个点拆成四个来控制方向:
如上图,每个点 ( 1 , 2 ) , ( 2 , 3 ) , ( 3 , 4 ) , ( 4 , 1 ) (1,2),(2,3),(3,4),(4,1) (1,2),(2,3),(3,4),(4,1)之间连代价为 0 0 0的无向边(转向),对于原图中的边,如 ( A , B ) (A,B) (A,B),连边 ( A 2 , B 1 ) , ( A 3 , B 4 ) (A2,B1),(A3,B4) (A2,B1),(A3,B4)
蓝色路线为最短路DAG上的边,注意必须经过这条边,所以不能切断它——即不能连接
(
A
1
,
A
4
)
,
(
A
2
,
A
3
)
,
(
B
1
,
B
4
)
,
(
B
4
,
B
3
)
.
.
.
(A1,A4),(A2,A3),(B1,B4),(B4,B3)...
(A1,A4),(A2,A3),(B1,B4),(B4,B3)...
同样不能走到城市里面去,假设
A
B
C
D
ABCD
ABCD围成一个城市,则
A
3
,
B
4
,
C
2
,
D
1
A3,B4,C2,D1
A3,B4,C2,D1都不能走到。
强制不走左上角的 1 1 1,求左上角的 2 2 2到 4 4 4的最短路就是答案。
代码
#include<bits/stdc++.h>
#define fi first
#define sc second
#define gc getchar
#define pb push_back
#define rc(x,y) (((x-1))*(m+1)+(y))
#define RC(x,y,z) (((rc(x,y)-1)<<2)+z)
using namespace std;
const int N=404,MX=7e5+10,M=1e7+10;
typedef long long ll;
const ll inf=0x7f7f7f7f7f7f7f7f;
typedef double db;
int n,m,lim,pre[MX];
int hv[N][N],dn[N][N],rt[N][N];
int head[MX],to[M],nxt[M],w[M],tot;
ll dis[MX];bool ban[MX],vs[N*N],tg[MX];
char cp;
template<class T>inline void rd(T &x)
{
cp=gc();x=0;int f=0;
for(;!isdigit(cp);cp=gc()) if(cp=='-') f=1;
for(;isdigit(cp);cp=gc()) x=x*10+(cp^48);
if(f) x=-x;
}
inline void lk(int u,int v,int vv)
{
if(ban[u] || ban[v]) return;
to[++tot]=v;nxt[tot]=head[u];head[u]=tot;w[tot]=vv;
to[++tot]=u;nxt[tot]=head[v];head[v]=tot;w[tot]=vv;
}
struct P{
int id;ll v;
bool operator <(const P&ky)const{
return v>ky.v;
}
}tp;
priority_queue<P>que;
void dij(int st)
{
int i,j,x;
memset(dis,0x7f,sizeof(ll)*(lim+1));
dis[st]=0;que.push((P){st,0LL});
for(;!que.empty();){
tp=que.top();que.pop();x=tp.id;
if(dis[x]!=tp.v) continue;
for(i=head[x];i;i=nxt[i]){
j=to[i];if(dis[j]<=dis[x]+w[i]) continue;
pre[j]=x;dis[j]=dis[x]+w[i];
que.push((P){j,dis[j]});
}
}
}
void mk(int x)
{
if(vs[x] || !pre[x]) return;
vs[x]=true;int y=pre[x],X=(x-1)<<2,Y=(y-1)<<2;
if(y==x-1) tg[Y+2]=tg[X+4]=1;
else if(y==x+1) tg[X+2]=tg[Y+4]=1;
else if(y==x-m-1) tg[Y+3]=tg[X+1]=1;
else tg[X+3]=tg[Y+1]=1;
mk(y);
}
int main(){
int i,j,k,x,y;
rd(n);rd(m);
for(i=1;i<=n;++i)
for(j=1;j<=m;++j)
rd(hv[i][j]);
for(i=1;i<=n;++i)
for(j=1;j<=m+1;++j){
rd(dn[i][j]);
lk(rc(i,j),rc(i+1,j),dn[i][j]);
}
for(i=1;i<=n+1;++i)
for(j=1;j<=m;++j){
rd(rt[i][j]);
lk(rc(i,j),rc(i,j+1),rt[i][j]);
}
lim=(n+1)*(m+1);dij(1);
memset(head,0,sizeof(int)*(lim+1));tot=0;
for(i=1;i<=n;++i)
for(j=1;j<=m;++j)
if(hv[i][j]){
mk(rc(i,j));
ban[RC(i,j,3)]=ban[RC(i,j+1,4)]=ban[RC(i+1,j,2)]=ban[RC(i+1,j+1,1)]=true;
}
ban[1]=true;
for(i=1;i<=n+1;++i)
for(j=1;j<=m+1;++j)
for(x=(rc(i,j)-1)<<2,k=1;k<=4;++k)
if(!tg[x+k]) lk(x+k,x+k%4+1,0);
for(i=1;i<=n;++i)
for(j=1;j<=m+1;++j)
lk(RC(i,j,3),RC(i+1,j,2),dn[i][j]),
lk(RC(i+1,j,1),RC(i,j,4),dn[i][j]);
for(i=1;i<=n+1;++i)
for(j=1;j<=m;++j)
lk(RC(i,j,2),RC(i,j+1,1),rt[i][j]),
lk(RC(i,j+1,4),RC(i,j,3),rt[i][j]);
lim<<=2;dij(2);
printf("%lld",dis[4]);
return 0;
}