XDOJ 1202: The Offer - Lunatic
XDOJ 1202: The Offer - Lunatic
题目链接:http://acm.xidian.edu.cn/problem.php?id=1202
题目大意:给定一个$n \times m$的网格图,每个格子上有值$h[i][j]$。有两种移动方式:1.移动到相邻的格子(代价为原位置和移动后位置上的值之和);2.在给定的$k$个矩形内,若两个格子值相差不超过$p[k]$,则可互相移动(代价为$t[k]$)。现给定起点坐标和终点坐标,问最小代价。
Dijkstra
关键在于建图,建好图后直接跑最短路就好了。
给每个矩形设$3 \times 101$个虚点,将该矩形内$h[i][j]=x$的点分别与三个虚点$d_x^1,d_x^2,d_x^3$相连(其中$d_x^1$指向点$(i,j)$(边长为$0$),点$(i,j)$指向$d_x^2$(边长为$0$),$d_x^3$与点$(i,j)$互相连接(边长为$t[k]$)),最后将符合条件($fabs(a-b) \leqslant p[k]$)的$d_a^1$点与$d_b^2$点相连接(边长为$2 \times t[k]$)。
(考虑到$t[k]$可能不能被$2$整除,将所有边长乘$2$,再将结果除$2$)。
具体结构如下图所示(请叫我灵魂画师,不接受批评歇歇):
最后将相邻格子互相连边,跑下Dijkstra即可。
建图复杂度为$O(rn^2MAX\{h[i][j]\})$,故总复杂度为$O(rn^2MAX\{h[i][j]\}+n^2logn)$.
代码如下:
1 #include <iostream> 2 #include <cstdio> 3 #include <vector> 4 #include <queue> 5 #define N 105 6 #define R 15 7 #define X first 8 #define Y second 9 using namespace std; 10 typedef long long ll; 11 typedef pair<ll,ll> P; 12 const ll inf=1000000000000000LL; 13 ll CASE,mp[N][N],n,m,r,t[R],p[R],dis[N*N+3*R*N]; 14 bool vis[N*N+3*R*N]; 15 P a[R],b[R],S,T; 16 struct edge{ 17 ll to,w; 18 edge(ll T,ll W){to=T;w=W;} 19 }; 20 struct node{ 21 ll u,d; 22 node(ll U,ll D){u=U;d=D;} 23 bool operator < (const node x)const{return d>x.d;} 24 }; 25 vector<edge>e[N*N+3*R*N]; 26 priority_queue<node>q; 27 void init(){ 28 for(ll i=0;i<n*m+3*101*r;++i)e[i].clear(); 29 for(ll k=0;k<r;++k){ 30 ll bs=n*m+k*3*101; 31 for(ll i=a[k].X;i<=b[k].X;++i){ 32 for(ll j=a[k].Y;j<=b[k].Y;++j){ 33 ll d1=bs+3*mp[i][j],d2=bs+3*mp[i][j]+1,d3=bs+3*mp[i][j]+2; 34 e[d1].push_back(edge(i*m+j,0)); 35 e[i*m+j].push_back(edge(d2,0)); 36 e[d3].push_back(edge(i*m+j,t[k])); 37 e[i*m+j].push_back(edge(d3,t[k])); 38 } 39 } 40 for(ll i=0;i<=100;i++){ 41 for(ll j=i;j<=i+p[k]&&j<=100;j++){ 42 e[bs+3*i+1].push_back(edge(bs+3*j,2*t[k])); 43 e[bs+3*j+1].push_back(edge(bs+3*i,2*t[k])); 44 } 45 } 46 } 47 for(ll i=0;i<n;++i){ 48 for(ll j=0;j<m;++j){ 49 int k=i*m+j; 50 if(i!=0)e[k].push_back(edge((i-1)*m+j,2*(mp[i][j]+mp[i-1][j]))); 51 if(i!=n-1)e[k].push_back(edge((i+1)*m+j,2*(mp[i][j]+mp[i+1][j]))); 52 if(j!=0)e[k].push_back(edge(i*m+j-1,2*(mp[i][j]+mp[i][j-1]))); 53 if(j!=m-1)e[k].push_back(edge(i*m+j+1,2*(mp[i][j]+mp[i][j+1]))); 54 } 55 } 56 } 57 ll dijkstra(ll s,ll d){ 58 ll tot=n*m+3*101*r; 59 for(ll i=0;i<tot;++i){ 60 dis[i]=inf; 61 vis[i]=0; 62 } 63 dis[s]=0; 64 while(!q.empty())q.pop(); 65 q.push(node(s,0)); 66 while(!q.empty()){ 67 node t=q.top();q.pop(); 68 ll u=t.u; 69 if(vis[u])continue; 70 vis[u]=1; 71 for(ll i=0;i<(ll)e[u].size();++i){ 72 ll v=e[u][i].to,w=e[u][i].w; 73 if(dis[u]+w<dis[v]){ 74 dis[v]=dis[u]+w; 75 q.push(node(v,dis[v])); 76 } 77 } 78 } 79 return dis[d]; 80 } 81 int main(void){ 82 scanf("%lld",&CASE); 83 while(CASE--){ 84 scanf("%lld%lld%lld",&n,&m,&r); 85 for(ll i=0;i<n;++i) 86 for(ll j=0;j<m;++j) 87 scanf("%lld",&mp[i][j]); 88 for(ll i=0;i<r;++i){ 89 scanf("%lld%lld",&a[i].X,&a[i].Y); 90 scanf("%lld%lld",&b[i].X,&b[i].Y); 91 a[i].X--,a[i].Y--,b[i].X--,b[i].Y--; 92 scanf("%lld%lld",&t[i],&p[i]); 93 } 94 scanf("%lld%lld",&S.X,&S.Y); 95 scanf("%lld%lld",&T.X,&T.Y); 96 S.X--,S.Y--,T.X--,T.Y--; 97 init(); 98 ll ans=dijkstra(S.X*m+S.Y,T.X*m+T.Y)/2; 99 printf("%lld\n",ans); 100 } 101 }