洛谷 P3786 萃香抱西瓜
P3786 萃香抱西瓜 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)(题面太长了,复制过来很麻烦)
他看上去像一个状压dp,而且t,h,w,m的范围都很小,就直接设计一个dp[i][x][y][f]表示在第i秒,角色位置在(x,y),目前抱西瓜的状态为f时最少要走的步数。
然后可以发现t只能向t+1转移,符合DAG的性质,可以放心打dp,但是每次遍历还需要判断能不能走,似乎很麻烦(?
(突然发现可以预处理每个时间点的每个位置能不能到达)
定义一个数组can[t][x][y]表示t时间时(x,y)能不能到达,还有一个flag[t][x][y]数组表示在t时间时在(x,y)的西瓜编号
(注意转移的时候不要漏判可以原地不动的情况,还有dp的初始化,如果一开始在出发点有小西瓜是要初始化进去的)
(dp的转移方程在代码里看吧)
可能全分有点困难,下面还有部分分的得分方法(如果我能看出来的话之后的博客都会有):
子任务 1:所有西瓜静止,且不需要捡任何一个
做法:直接判断初始位置有没有大西瓜即可
子任务 2~3:所有西瓜静止,需要捡小于10个西瓜
做法:因为需要捡的数量最多只有10个,而且不动,可以直接状压跑最短路或者dp求解
子任务4~5:西瓜会运动,不需要捡西瓜
做法:按时间将图分层,然后跑最短路或者dp
子任务1~10:(最开始)
代码:
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
long long h,w,t,sx,sy,n,m;
long long dp[105][6][6][1<<10+1];
inline long long read(){
long long s=0,f=1;
char c=getchar();
while(!isdigit(c)){
if(c=='-'){
f=-f;
}
c=getchar();
}
while(isdigit(c)){
s=(s<<3)+(s<<1)+(c^48);
c=getchar();
}
return s*f;
}
long long can[105][6][6],flag[105][6][6];
int main(){
memset(dp,0x3f,sizeof(dp));
h=read();
w=read();
t=read();
sx=read();
sy=read();
for(int i=1;i<=t;i++){
for(int j=1;j<=h;j++){
for(int k=1;k<=w;k++){
can[i][j][k]=1;
}
}
}
n=read();
m=read();
long long wz=0,tm1=0,tm2=0,x,y,ok=0;
for(int i=1;i<=n;i++){
tm1=read();
tm2=read();
ok=read();
if(ok==1){
wz++;
for(int j=tm1;j<tm2;j++){
x=read();
y=read();
flag[j][x][y]=wz;
}
}else
{
for(int j=tm1;j<tm2;j++){
x=read();
y=read();
can[j][x][y]=0;
}
}
}
if(can[1][sx][sy]==0){
cout<<-1<<endl;
}
if(flag[1][sx][sy]!=0){
dp[1][sx][sy][1<<(flag[1][sx][sy]-1)]=0;
}else
{
dp[1][sx][sy][0]=0;
}
for(int i=1;i<=t;i++){
for(int j=1;j<=h;j++){
for(int k=1;k<=w;k++){
for(int now=0;now<(1<<m);now++){
if(dp[i][j][k][now]==4557430888798830399){
continue;
}
if(can[i+1][j-1][k]){
if(flag[i+1][j-1][k]){
dp[i+1][j-1][k][now|(1<<(flag[i+1][j-1][k]-1))]=min(dp[i+1][j-1][k][now|(1<<(flag[i+1][j-1][k]-1))],dp[i][j][k][now]+1);
}else{
dp[i+1][j-1][k][now]=min(dp[i+1][j-1][k][now],dp[i][j][k][now]+1);
}
}
if(can[i+1][j][k-1]){
if(flag[i+1][j][k-1]){
dp[i+1][j][k-1][now|(1<<(flag[i+1][j][k-1]-1))]=min(dp[i+1][j][k-1][now|(1<<(flag[i+1][j][k-1]-1))],dp[i][j][k][now]+1);
}else{
dp[i+1][j][k-1][now]=min(dp[i+1][j][k-1][now],dp[i][j][k][now]+1);
}
}
if(can[i+1][j+1][k]){
if(flag[i+1][j+1][k]){
dp[i+1][j+1][k][now|(1<<(flag[i+1][j+1][k]-1))]=min(dp[i+1][j+1][k][now|(1<<(flag[i+1][j+1][k]-1))],dp[i][j][k][now]+1);
}else{
dp[i+1][j+1][k][now]=min(dp[i+1][j+1][k][now],dp[i][j][k][now]+1);
}
}
if(can[i+1][j][k+1]){
if(flag[i+1][j][k+1]){
dp[i+1][j][k+1][now|(1<<(flag[i+1][j][k+1]-1))]=min(dp[i+1][j][k+1][now|(1<<(flag[i+1][j][k+1]-1))],dp[i][j][k][now]+1);
}else{
dp[i+1][j][k+1][now]=min(dp[i+1][j][k+1][now],dp[i][j][k][now]+1);
}
}
if(can[i+1][j][k]){
if(flag[i+1][j][k]){
dp[i+1][j][k][now|(1<<(flag[i+1][j][k]-1))]=min(dp[i+1][j][k][now|(1<<(flag[i+1][j][k]-1))],dp[i][j][k][now]);
}else{
dp[i+1][j][k][now]=min(dp[i+1][j][k][now],dp[i][j][k][now]);
}
}
}
}
}
}
long long fk=0,ans=999999999;
for(int i=1;i<=h;i++){
for(int j=1;j<=w;j++){
if(dp[t][i][j][(1<<m)-1]==4557430888798830399){
continue;
}
ans=min(ans,dp[t][i][j][(1<<m)-1]);
fk=1;
}
}
if(fk==0){
cout<<-1<<endl;
}else{
cout<<ans<<endl;
}
return 0;
}
(谢谢观看!)

浙公网安备 33010602011771号