您的位置:首页 > 产品设计 > UI/UE

2015 UESTC Training for Dynamic Programming 男神的约会 BFS+状压DP

2016-03-05 10:53 387 查看
D - 男神的约会
Time Limit:1000MS Memory Limit:65535KB 64bit IO Format:%lld & %llu
Submit Status Practice UESTC
1134

Appoint description:
System Crawler (2016-03-02)

Description

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

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

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

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

Input

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

Output

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

Sample Input

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

Sample Output

50

Hint
题意:从(0,0)到(9,9)要求只能想右或者向下并领取所有的优惠券(各种不同的数字代表不同的优惠券),求最少所用的时间。

思路:从最少的时间大概能想到有BFS,但是对于判断当前领取的优惠卷就百思不得其解了,最后看了一下别人的思路才略有思路,因为每次只能向下或者向右,所以当前状态(i,j)只与(i-1,j)和(i,j-1)有关,所以就可以得出状态转移方程:dp[i][j][k|(1<<g[i][j])] = min(dp[i-1][j][k],dp[i][j-1][k])+g[i][j];(i-1,j)和(i,j-1)保证在范围内。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <string>
#include <queue>
#include <cmath>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
int g[12][12],dp[12][12][1<<11];
//dp[i][j][k]表示从坐标(0,0)走到当前坐标(i,j)而且当前状态为k时所使用的最少时间
int dir[2][2] = {{1,0},{0,1}};//两个方向(右或下)
bool vis[12][12][1<<11];//标记每个点是否走过
struct Point
{
int x,y,k;
Point(int _x = 0,int _y = 0,int _k = 0):x(_x),y(_y),k(_k){};
};
void BFS()
{
memset(vis,false,sizeof(vis));
memset(dp,inf,sizeof(dp));
Point head,next;
queue<Point>q;
Point p(0,0,1<<g[0][0]);
vis[p.x][p.y][p.k] = true;
dp[p.x][p.y][p.k] = g[p.x][p.y];
q.push(p);
while(!q.empty())
{
head = q.front(); q.pop();
for(int i = 0; i<2; i++)//两个方向(右或下)
{
next.x = head.x + dir[i][0];
next.y = head.y + dir[i][1];
if(next.x >= 0 && next.x <10 && next.y >= 0 && next.y <10)//判断是否出界了
{
next.k = head.k|(1<<g[next.x][next.y]);//每走一步就把当前优惠券号标记住
dp[next.x][next.y][next.k] = min(dp[next.x][next.y][next.k],dp[head.x][head.y][head.k]+g[next.x][next.y]);
if(!vis[next.x][next.y][next.k])//判断当前坐标是否走过了
{
q.push(next);
vis[next.x][next.y][next.k] = true;
}
}
}
}
}
int main()
{
#ifdef CDZSC_June
freopen("t.txt","r",stdin);
#endif
for(int i = 0; i<10; i++)
{
for(int j = 0; j<10; j++)
{
scanf("%d",&g[i][j]);
}
}
BFS();
printf("%d\n",dp[9][9][(1<<10) - 1]);//(1<<10) - 1)代表的是全部的优惠卷都领取了
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: