这题作为学单调队列优化DP入门差不多。。
看了一两天的单调队列 差不多弄懂了。。
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#include<queue>
#include<algorithm>
#include<vector>
using namespace std;
#define maxn 1010
#define inf 9999999
typedef long long ll;
struct node
{
int pos,cost;
};
node a[60][maxn];
int dp[60][maxn];
int q[maxn],head,tail;
int solve(int i,int k,int j)
{
return dp[i-1][k]+abs(a[i-1][k].pos-a[i][j].pos)+a[i][j].cost;
}
bool cmp(const node&a,const node&b)
{
return a.pos<b.pos;
}
int main()
{
freopen("in.txt","r",stdin);
int t;
scanf("%d",&t);
int m,n,x;
while(t--)
{
scanf("%d%d%d",&m,&n,&x);
int i,j,k;
for(i=1;i<=m;i++)
{
for(j=1;j<=n;j++)
scanf("%d",&a[i][j].pos);
}
for(i=1;i<=m;i++)
{
for(j=1;j<=n;j++)
{
dp[i][j]=inf;
scanf("%d",&a[i][j].cost);
}
sort(a[i]+1,a[i]+n+1,cmp);
}
for(i=1;i<=n;i++)
dp[1][i]=abs(x-a[1][i].pos)+a[1][i].cost;
for(i=2;i<=m;i++)
{
head=0,tail=0;
for(j=k=1;j<=n;j++)//从前往后搜上一个状态的位置,如果小于当前j的位置,则一定小于j+1的位置
{
while(k<=n&&a[i-1][k].pos<=a[i][j].pos)
{
int res=solve(i,k,j);
while(head<tail&&solve(i,q[tail-1],j)>=res)//维护一个单调队列,保存比它小的位置转移到它的最小费用q[head]是优的那个位置
tail--;
q[tail++]=k;
k++;
}
if(head<tail)
dp[i][j]=min(dp[i][j],solve(i,q[head],j));
}
head=0,tail=0;
for(j=k=n;j>=1;j--)//同理,从后往前搜
{
while(k>=1&&a[i-1][k].pos>a[i][j].pos)
{
int res=solve(i,k,j);
while(head<tail&&solve(i,q[tail-1],j)>=res)//同上
tail--;
q[tail++]=k;
k--;
}
if(head<tail)
dp[i][j]=min(dp[i][j],solve(i,q[head],j));
}
}
int ans=inf;
for(i=1;i<=n;i++)
{
if(dp[m][i]<ans)
ans=dp[m][i];
}
printf("%d\n",ans);
}
return 0;
}