hdu 4362 (단조로운 대기열 최적화 dp)
4544 단어 dp
문제풀이 사고방식: dp[i][j]는 i단계에서 j번째 용구슬의 최소 소모 에너지를 선택한 것을 나타낸다.
전이 방정식: dp[i][j]=min{dp[i-1][k]+abs(loc[i][j]-loc[i-1][k])+cost[i][j]}, 여기에 매거해야 하는 것은 i, j, k이기 때문에 시간 복잡도 O(M*N*N)이다. 이 문제는 데이터가 빡빡하지 않은 것 같아서 운이 좋으면 AC할 수 있다.근데 정해는 아니야.
이곳은 단조로운 대열을 이용할 수 있다.dp[i][j]=min{dp[i-1][k]-loc[i-1][k]+loc[i][j]+cost[i][j]}(loc[i][j]>loc[i-1][k])) 때문에 dp[i-1][k]-loc[i-1][k]만 유지하면 됩니다.절대값이 있기 때문에 저는 두 개의 단조로운 대기열을 사용했습니다. 하나는 dp[i-1][k]-loc[i-1][k]를 유지하고 다른 하나는 dp[i-1][k]+loc[i-1][k]를 유지하지만 무슨 이유로WA를 사용했는지 모르겠습니다.
우선 여기에 놓고 나중에 생각이 나면 고치자.내 블로그를 지나가는 어떤 대신의 조언도 바랍니다.
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 1005;
const int inf = 0x3f3f3f3f;
struct Node
{
int pos,cost;
}mat[55][maxn];
int n,m,x;
int dp[55][maxn],q1[maxn],q2[maxn],h1,h2,t1,t2;
bool cmp(Node a,Node b)
{
return a.pos < b.pos;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d%d%d",&m,&n,&x);
memset(dp,inf,sizeof(dp));
for(int i = 1; i <= m; i++)
for(int j = 1; j <= n; j++)
scanf("%d",&mat[i][j].pos);
for(int i = 1; i <= m; i++)
{
for(int j = 1; j <= n; j++)
scanf("%d",&mat[i][j].cost);
sort(mat[i]+1,mat[i]+1+n,cmp);<span style="white-space:pre"> </span>// ,
}
for(int i = 1; i <= n; i++)
dp[1][i] = abs(x - mat[1][i].pos) + mat[1][i].cost;
for(int i = 2; i <= m; i++)
{
h1 = h2 = t1 = t2 = 0;
for(int j = 1; j <= n; j++) // dp[i-1]
{
while(h1 < t1 && dp[i-1][j] - mat[i-1][j].pos <= dp[i-1][q1[t1-1]] - mat[i-1][q1[t1-1]].pos) t1--;
q1[t1++] = j;
while(h2 < t2 && dp[i-1][j] + mat[i-1][j].pos <= dp[i-1][q2[t2-1]] + mat[i-1][q2[t2-1]].pos) t2--;
q2[t2++] = j;
}
for(int j = 1; j <= n; j++)
{
while(h1 < t1 && mat[i][j].pos < mat[i-1][q1[h1]].pos) h1++;
dp[i][j] = dp[i-1][q1[h1]] + mat[i][j].pos + mat[i][j].cost;
while(h2 < t2 && mat[i][j].pos >= mat[i-1][q2[h2]].pos) h2++;
dp[i][j] = min(dp[i][j],dp[i-1][q2[h2]] - mat[i][j].pos + mat[i][j].cost);
}
}
int ans = inf;
for(int i = 1; i <= n; i++)
ans = min(ans,dp[m][i]);
printf("%d
",ans);
}
return 0;
}
PS: 자세히 생각해 보니까 확실히 자신의 단조로운 대기열에 문제가 있다. 왜냐하면 내가 모든 dp[i-1]층을 대기열에 먼저 넣었기 때문에 문제가 발생할 수 있다. 내 뒤에 dp[i]층을 반복적으로 열거할 때 유효한 위치가 대기열에 없을 수도 있다.그래서 다른 사람의 코드를 참고했는데 dp[i][j]의 j를 먼저 열거해야 한다. 내가 먼저 j의 위치를 선택할 것을 보증한다. 이미 질서가 있기 때문에 mat[i][j]보다 크지 않다.pos 위치의 최소값은 된다. 같은 이치로 절대값이 있기 때문에 반대로 한 번 순환해야 한다.
자세한 절차는 코드를 참조하십시오.
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 1005;
const int inf = 0x3f3f3f3f;
struct Node
{
int pos,cost;
}mat[55][maxn];
int n,m,x;
int dp[55][maxn],q1[maxn],q2[maxn],h1,h2,t1,t2;
bool cmp(Node a,Node b)
{
return a.pos < b.pos;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d%d%d",&m,&n,&x);
memset(dp,inf,sizeof(dp));
for(int i = 1; i <= m; i++)
for(int j = 1; j <= n; j++)
scanf("%d",&mat[i][j].pos);
for(int i = 1; i <= m; i++)
{
for(int j = 1; j <= n; j++)
scanf("%d",&mat[i][j].cost);
sort(mat[i]+1,mat[i]+1+n,cmp);
}
for(int i = 1; i <= n; i++)
dp[1][i] = abs(x - mat[1][i].pos) + mat[1][i].cost;
for(int i = 2; i <= m; i++)
{
int k = 1, Min = inf;
for(int j = 1; j <= n; j++)
{
while(k <= n && mat[i][j].pos >= mat[i-1][k].pos)
{
Min = min(Min,dp[i-1][k] - mat[i-1][k].pos);
k++;
}
dp[i][j] = Min + mat[i][j].pos + mat[i][j].cost;
}
k = n, Min = inf;
for(int j = n; j >= 1; j--)
{
while(k >= 1 && mat[i][j].pos <= mat[i-1][k].pos)
{
Min = min(Min,dp[i-1][k] + mat[i-1][k].pos);
k--;
}
dp[i][j] = min(dp[i][j],Min - mat[i][j].pos + mat[i][j].cost);
}
}
int ans = inf;
for(int i = 1; i <= n; i++)
ans = min(ans,dp[m][i]);
printf("%d
",ans);
}
return 0;
}
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
【경쟁 프로 전형적인 90문】008의 해설(python)의 해설 기사입니다. 해설의 이미지를 봐도 모르는 (이해력이 부족한) 것이 많이 있었으므로, 나중에 다시 풀었을 때에 확인할 수 있도록 정리했습니다. ※순차적으로, 모든 문제의 해설 기사를 들어갈 예정입니다. 문자열...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.