[dp][uestc oj]J - 男神的约会

J - 男神的约会

Time Limit: 3000/1000MS (Java/Others)     Memory Limit: 65535/65535KB (Java/Others)
Submit Status

有一天男神约了学姐姐去看电影,电影院有一个活动,给你一个10*10的矩阵,每一个格子上都有一个0-9的整数,表示一共十种优惠券中的一种。

观众从左上角的格子开始走,走到右下角。每走到一个有着a号优惠券的格子,都必须要玩一个a分钟的游戏来领取这张优惠券。

每次只能向右或向下走。当走到右下角的时候,如果集齐10种优惠券就可以半价看电影呢。

为了能在学姐姐面前展示自己的才智,男神准备用最少的时间领取全部的优惠券(他要省出最多的时间陪学姐姐)。聪明的你能告诉男神,他最少要花费的时间是多少?

Input

输入包含10行,每行10个数字,以空格隔开,表示格子上的优惠券的种类。数据保证存在合法路径。

Output

输出男神走到右下角的最小时间花费。

Sample input and output

Sample InputSample Output
0 1 2 3 4 5 6 7 8 9
1 1 1 1 1 1 1 1 1 0
2 1 1 1 1 1 1 1 1 0
3 1 1 1 1 1 1 1 1 0
4 1 1 1 1 1 1 1 1 0
5 1 1 1 1 1 1 1 1 0
6 1 1 1 1 1 1 1 1 0
7 1 1 1 1 1 1 1 1 0
8 1 1 1 1 1 1 1 1 0
9 1 1 1 1 1 1 1 1 5
50

影响当前决策的有所在的位置和收集过的优惠劵因此定义状态dp[i][j][sta]为到i,j位置sta状态的最小花费,问题来了,sta怎么表示,比较好的办法是用一个二进制,一位对应一种优惠劵,0表示没有收集过,1表示收集过。状态转移方程dp[i][j][st|1<<mp[i][j]]=min(dp[i-1][j][st],dp[i][j-1][st]|(i-1,j)+mp[i][j],(i,j-1)合法,st相等),注意递推顺序应该是由左上角往右下斜着推,用一个队列来实现。

memset是按字节赋值的,so。int只有赋值-1和0才会对应-1和0

#include<cstdio>
#include<memory.h>
#include<queue>
#include<algorithm>
using namespace std;

const int MAXSTA=0x3ff;
const int MAXij=11;
//const int SIGN=16843009;//0x01010101
int dp[MAXij][MAXij][MAXSTA];

int mp[MAXij][MAXij];
bool vis[MAXij][MAXij][MAXSTA];
int solve()
{
  queue<int>qi;
  queue<int>qj;
  queue<int>qst;
  int ci=0,cj=0,cst=1<<mp[0][0];
  memset(dp,1,sizeof(dp));
  //memset(vis,0,sizeof(vis));
  dp[ci][cj][cst]=mp[0][0];

  int ni,nj,nst;
  do
  {
    if(ci<9){
      ni=ci+1,nj=cj;
      nst=cst|(1<<mp[ni][nj]);
      dp[ni][nj][nst]=min(dp[ni][nj][nst],dp[ci][cj][cst]+mp[ni][nj]);
      if(!vis[ni][nj][nst])
      {
        qi.push(ni);
        qj.push(nj);
        qst.push(nst);
        vis[ni][nj][nst]=true;
      }
    }
    if(cj<9){
      ni=ci,nj=cj+1;
      nst=cst|(1<<mp[ni][nj]);
      dp[ni][nj][nst]=min(dp[ni][nj][nst],dp[ci][cj][cst]+mp[ni][nj]);
     if(!vis[ni][nj][nst])
      {
        qi.push(ni);
        qj.push(nj);
        qst.push(nst);
        vis[ni][nj][nst]=true;
      }
    }
    ci=qi.front();
    cj=qj.front();
    cst=qst.front();
    qi.pop();
    qj.pop();
    qst.pop();
  }while(qi.size());
}

int main()
{
  //freopen("Jinput.txt","r",stdin);
  int i,j;
  for(i=0;i<10;i++)
    for(j=0;j<10;j++)
      scanf("%d",&mp[i][j]);

    solve();
  printf("%d",dp[9][9][MAXSTA]);
}

 

转载于:https://www.cnblogs.com/jerryRey/p/4523612.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值