不知不觉又好久没有写博客了。不能这样一直放着。在适当的时候总结一下,回首过去走过的,总会有一些感触和经验,写题解也是为了大体回忆一下自己的思路,让自己对这题掌握更深刻。暂停一下,是为了稳住前进的脚步,让将来的步伐迈得更加稳健。加油!
好了。。废话到此打住,上题。
这题之前雅礼集训的时候做过类似的,30分的状压设f[x,y,s]表示走到(x,y)各个关键点的状态为s的最短路。考试的时候直接写了30的,结果还写挂10分滚粗了。。。
正解》首先有个结论:最优解一定会把(起点到每个关键点的最短路径)包含在里面。
反证》如果某条最短路没有被包含,那么它和环一定会有两个交点,那么这两个交点在环上的距离就大于它在最短路中的距离,则不是最优解。(如下图,黑色为走出的环,蓝色为最短路,那么红色那段一定大于蓝色那段,即黑环不是最优解。
ok.现在有了这个结论,问题变成了,我们要从原点出发,绕一圈把那些最短路和特殊点都绕进来,所需要的最短路径是多少。
标解使用了拆点的做法。把原图的每个点拆成四个。这样原图中的一条边在新图中就变成了一个长方形(圈起来的)
因为要包含最短路径不能穿过它,所以我们把与原图中路径垂直的两条短边cut掉,平行的两条长边赋成原图的中的边权,就可以实现把最短路绕进去了。对于关键点,我们把它四周的边以及延伸出去的短边cut掉就可以了。最后跑一次从(1,2)到(2,1)的最短路,得到的即是Ans
#include<cstdio> #include<cstdlib> #include<algorithm> #include<cmath> #include<cstring> #include<queue> using namespace std; typedef long long ll; ll d[811][811],fz; int vis[811][811],c[11][11]; ll len[811][811][5],nl[811][811][5]; int cy[401*401][2],que[401*401][2]; int tc,n,m,i,j,k,x,y,nx,ny,tl; bool pe[402][402][5]; struct dd{ int x,y; ll dis; bool operator < (dd a) const { return dis>a.dis; }; }; priority_queue<dd> H; void dij(int sx,int sy) { dd st,now; int x,y,i,nx,ny; memset(d,127,sizeof(d)); d[sx][sy]=0; tl++; st.x=sx;st.y=sy;st.dis=0; H.push(st); while(!H.empty()){ now=H.top(); H.pop(); x=now.x;y=now.y; if(vis[x][y]==tl)continue; vis[x][y]=tl; for(i=1;i<=4;i++){ nx=x+c[i][0];ny=y+c[i][1]; if(nx<1||nx>n||ny<1||ny>m)continue; if(d[x][y]+len[x][y][i]<d[nx][ny]){ d[nx][ny]=d[x][y]+len[x][y][i]; st.x=nx;st.y=ny;st.dis=d[nx][ny]; H.push(st); } } } } void bfs(int sx,int sy) { int l,r,x,y,nx,ny,i; l=r=1; que[l][0]=sx;que[l][1]=sy; while(l<=r){ x=que[l][0];y=que[l][1]; for(i=1;i<=4;i++){ nx=x+c[i][0];ny=y+c[i][1]; if(nx<1||nx>n||ny<1||ny>m)continue; if(d[nx][ny]+len[x][y][i]==d[x][y]){ r++; que[r][0]=nx;que[r][1]=ny; pe[x][y][i]=false; if(i<=2)pe[nx][ny][3-i]=false; else pe[nx][ny][7-i]=false; } } l++; } } int main() { c[1][0]=0;c[1][1]=1;c[2][0]=0;c[2][1]=-1;c[3][0]=1;c[3][1]=0;c[4][0]=-1;c[4][1]=0; scanf("%d%d",&n,&m); for(i=1;i<=n;i++) for(j=1;j<=m;j++){ scanf("%d",&k); if(k==1){ tc++; cy[tc][0]=i;cy[tc][1]=j; } } for(i=1;i<=n;i++) for(j=1;j<=m+1;j++){ scanf("%d",&k); len[i][j][3]=k; len[i+1][j][4]=k; } for(i=1;i<=n+1;i++) for(j=1;j<=m;j++){ scanf("%d",&k); len[i][j][1]=k; len[i][j+1][2]=k; } memset(pe,true,sizeof(pe)); n++; m++; dij(1,1); for(i=1;i<=tc;i++)bfs(cy[i][0],cy[i][1]); for(i=1;i<=n;i++) for(j=1;j<=m;j++) for(k=1;k<=4;k++)if(len[i][j][k]){ x=i+c[k][0];y=j+c[k][1]; if(k==1){ nl[2*i-1][2*j][1]=nl[2*x-1][2*y-1][2]=len[i][j][k]; nl[2*i][2*j][1]=nl[2*x][2*y-1][2]=len[i][j][k]; if(!pe[i][j][k]){ nl[2*i-1][2*j][3]=nl[2*i][2*j][4]=1ll<<60; nl[2*i-1][2*j+1][3]=nl[2*i][2*j+1][4]=1ll<<60; } } if(k==3){ nl[2*i][2*j-1][3]=nl[2*x-1][2*y-1][4]=len[i][j][k]; nl[2*i][2*j][3]=nl[2*x-1][2*y][4]=len[i][j][k]; if(!pe[i][j][k]){ nl[2*i][2*j-1][1]=nl[2*i][2*j][2]=1ll<<60; nl[2*i+1][2*j-1][1]=nl[2*i+1][2*j][2]=1ll<<60; } } } for(i=1;i<=tc;i++){ x=cy[i][0];y=cy[i][1]; nl[2*x][2*y][1]=nl[2*x][2*y+1][2]=1ll<<60;nl[2*x][2*y-1][1]=nl[2*x][2*y][2]=1ll<<60;nl[2*x][2*y+1][1]=nl[2*x][2*y+2][2]=1ll<<60; nl[2*x+1][2*y][1]=nl[2*x+1][2*y+1][2]=1ll<<60;nl[2*x+1][2*y-1][1]=nl[2*x+1][2*y][2]=1ll<<60;nl[2*x+1][2*y+1][1]=nl[2*x+1][2*y+2][2]=1ll<<60; nl[2*x][2*y][3]=nl[2*x+1][2*y][4]=1ll<<60;nl[2*x-1][2*y][3]=nl[2*x][2*y][4]=1ll<<60;nl[2*x+1][2*y][3]=nl[2*x+2][2*y][4]=1ll<<60; nl[2*x][2*y+1][3]=nl[2*x+1][2*y+1][4]=1ll<<60;nl[2*x-1][2*y+1][3]=nl[2*x][2*y+1][4]=1ll<<60;nl[2*x+1][2*y+1][3]=nl[2*x+2][2*y+1][4]=1ll<<60; } nl[1][1][3]=nl[2][1][4]=1ll<<60;nl[1][2][3]=nl[2][2][3]=1ll<<60; nl[1][1][1]=nl[1][2][2]=1ll<<60;nl[2][1][1]=nl[2][2][2]=1ll<<60; for(i=1;i<=2*n;i++) for(j=1;j<=2*m;j++) for(k=1;k<=4;k++)len[i][j][k]=nl[i][j][k]; n*=2;m*=2; dij(1,2); printf("%lld ",d[2][1]); }