/*
分析:
优先队列+dp,思路同hdu4374。
读完题后很快就想到了hdu4374的解法、也不负众望的轻松ok了。
由于这个题不像hdu4374那样限制递推前后两个量的距离,所以可以不
用优先队列,既不需要每次从队列里面弹出极值、然后判断结果为可行才用
来递推;而是可以直接维护一个最值(代码中的mmin)、用O(1)的时间来直
接递推。时间复杂度O(n*m)。
2013-07-17
*/
分析:
优先队列+dp,思路同hdu4374。
读完题后很快就想到了hdu4374的解法、也不负众望的轻松ok了。
由于这个题不像hdu4374那样限制递推前后两个量的距离,所以可以不
用优先队列,既不需要每次从队列里面弹出极值、然后判断结果为可行才用
来递推;而是可以直接维护一个最值(代码中的mmin)、用O(1)的时间来直
接递推。时间复杂度O(n*m)。
2013-07-17
*/
#include"iostream"
#include"cstdio"
#include"queue"
#include"cstring"
using namespace std;
const int N=55;
const int M=1005;
const int inf=123456789;
int m,n,x;
struct node{
int dis,dig,dp;
}E[N][M];
int min(int a,int b){
return a>b?b:a;
}
int cmp(node n1,node n2){
return n1.dis<n2.dis;
}
int main()
{
int T;
int i,l,j;
int pre,mmin;
cin>>T;
while(T--)
{
cin>>m>>n>>x;
for(i=0;i<=m;i++)
for(l=1;l<=n;l++)
E[i][l].dp=inf;
E[0][1].dis=x;
E[0][1].dp=0;
sort(E[0]+1,E[0]+n+1,cmp);
for(i=1;i<=m;i++)
for(l=1;l<=n;l++)
scanf("%d",&E[i][l].dis);
for(i=1;i<=m;i++)
for(l=1;l<=n;l++)
scanf("%d",&E[i][l].dig);
for(i=1;i<=m;i++)
{
pre=i-1;
sort(E[i]+1,E[i]+n+1,cmp);
j=1;
mmin=inf;
for(l=1;l<=n;l++)
{
while(j<=n && E[pre][j].dis<=E[i][l].dis)
{
if(E[pre][j].dp - E[pre][j].dis<mmin)
mmin=E[pre][j].dp - E[pre][j].dis;
j++;
}
E[i][l].dp=min(E[i][l].dp,mmin+E[i][l].dis + E[i][l].dig);
}
j=n;
mmin=inf;
for(l=n;l>=1;l--)
{
while(1<=j && E[pre][j].dis>=E[i][l].dis)
{
if(E[pre][j].dp + E[pre][j].dis<mmin)
mmin=E[pre][j].dp + E[pre][j].dis;
j--;
}
E[i][l].dp=min(E[i][l].dp,mmin-E[i][l].dis + E[i][l].dig);
}
}
int ans=inf;
for(l=1;l<=n;l++) if(E[m][l].dp<ans) ans=E[m][l].dp;
cout<<ans<<endl;
}
return 0;
}