noip模拟赛 蒜头君救人
分析:之前的一道模拟赛题是dp+dfs,这道题是dp+bfs.
我们设f[stu][i][j]为当前状态为stu,走到(i,j)的答案,考虑怎么设计stu,每个人的状态有3种:要么在原地,要么被背着,要么已经到了终点,那么用一个3进制数保存就可以了.
下面考虑怎么转移,直接递推肯定是不对的,dfs也不行,只能bfs了.我们每次可以选择不走,或者如果当前点有人就背起来,或者到了终点就放下所有人或者放下所有使速度变慢的人,写好几次转移就过了.
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm> using namespace std;
const int inf = 0x7ffffff; int n, m, k, top, sx, sy, tx, ty, a[][], speed[], f[][][], dx[] = { , -, , }, dy[] = { , , , - },flag[];
char name[][],s[][]; struct node
{
int x, y, zhuangtai;
}; int jisuan(int stu)
{
int tot = ,sped = k;
memset(flag, , sizeof(flag));
while (stu)
{
tot++;
flag[tot] = stu % ;
stu /= ;
}
for (int i = ; i <= top; i++)
if (flag[i] == )
sped += speed[i];
if (sped < )
sped = ;
return sped;
} bool judge(int x, int y)
{
if (x >= && x <= n && y >= && y <= m)
return true;
return false;
} int bei(int stu, int x, int y)
{
int cur, tot = ;
for (int i = ; i <= top; i++)
if (s[x][y] == name[i][])
{
cur = i;
break;
}
memset(flag, , sizeof(flag));
while (stu)
{
tot++;
flag[tot] = stu % ;
stu /= ;
}
if (flag[cur])
return ;
flag[cur] = ;
for (int i = top; i >= ; i--)
stu = stu * + flag[i];
return stu;
} int fang1(int stu, int x, int y)
{
memset(flag, , sizeof(flag));
int tot = ;
while (stu)
{
tot++;
flag[tot] = stu % ;
stu /= ;
}
for (int i = ; i <= top; i++)
if (flag[i] == )
flag[i] = ;
for (int i = top; i >= ; i--)
stu = stu * + flag[i];
return stu;
} int fang2(int stu, int x, int y)
{
int tot = ;
memset(flag, , sizeof(flag));
while (stu)
{
tot++;
flag[tot] = stu % ;
stu /= ;
}
for (int i = ; i <= top; i++)
if (flag[i] == && speed[i] > )
flag[i] = ;
for (int i = top; i >= ; i--)
stu = stu * + flag[i];
return stu;
} int qpow(int a, int b)
{
int res = ;
while (b)
{
if (b & )
res *= a;
a *= a;
b >>= ;
}
return res;
} void bfs()
{
queue <node> q;
node temp;
temp.x = sx;
temp.y = sy;
temp.zhuangtai = ;
q.push(temp);
while (!q.empty())
{
node u = q.front();
q.pop();
int sudu = jisuan(u.zhuangtai),x = u.x,y = u.y;
//printf("%d %d %d\n", sudu, x, y);
for (int i = ; i < ; i++)
{
int nx = x + dx[i], ny = y + dy[i];
if (judge(nx, ny))
{
//只移动
if (s[nx][ny] != '#' && f[u.zhuangtai][nx][ny] > f[u.zhuangtai][x][y] + sudu)
{
f[u.zhuangtai][nx][ny] = f[u.zhuangtai][x][y] + sudu;
node temp;
temp.x = nx;
temp.y = ny;
temp.zhuangtai = u.zhuangtai;
q.push(temp);
}
//背人
if (s[nx][ny] >= 'A' && s[nx][ny] <= 'Z')
{
int stu = bei(u.zhuangtai, nx, ny);
if (f[stu][nx][ny] > f[u.zhuangtai][x][y] + sudu)
{
f[stu][nx][ny] = f[u.zhuangtai][x][y] + sudu;
node temp;
temp.zhuangtai = stu;
temp.x = nx;
temp.y = ny;
q.push(temp);
}
}
//放人
if (s[nx][ny] == 't')
{
int stu1 = fang1(u.zhuangtai, nx, ny);
int stu2 = fang2(u.zhuangtai, nx, ny);
if (f[stu1][nx][ny] > f[u.zhuangtai][x][y] + sudu)
{
f[stu1][nx][ny] = f[u.zhuangtai][x][y] + sudu;
node temp;
temp.zhuangtai = stu1;
temp.x = nx;
temp.y = ny;
q.push(temp);
}
if (f[stu2][nx][ny] > f[u.zhuangtai][x][y] + sudu)
{
f[stu2][nx][ny] = f[u.zhuangtai][x][y] + sudu;
node temp;
temp.zhuangtai = stu2;
temp.x = nx;
temp.y = ny;
q.push(temp);
}
}
}
}
}
} int main()
{
scanf("%d%d%d", &n, &m, &k);
for (int i = ; i <= n; i++)
{
scanf("%s", s[i] + );
for (int j = ; j <= m; j++)
{
if (s[i][j] == 's')
{
sx = i;
sy = j;
}
else
{
if (s[i][j] == 't')
{
tx = i;
ty = j;
}
else
{
if (s[i][j] >= 'A' && s[i][j] <= 'Z')
top++;
}
}
}
}
for (int i = ; i <= top; i++)
scanf("%s%d", name[i], &speed[i]);
for (int i = ; i <= ; i++)
for (int j = ; j <= ; j++)
for (int l = ; l <= ; l++)
f[i][j][l] = inf;
f[][sx][sy] = ;
bfs();
printf("%d\n", f[qpow(, top) - ][tx][ty]); return ;
}
noip模拟赛 蒜头君救人的更多相关文章
- noip模拟赛 蒜头君的兔子
分析:直接暴力算有30分,像斐波那契那样推式子算有60分,如果想要得到100分就要用一种数列题的常见优化--矩阵了. 当前的兔子数和十年内的兔子数有关,我们需要1个1*11的矩阵,来记录当前为0岁.1 ...
- noip模拟赛 蒜头君的排序
分析:其实就是求m个区间的逆序对个数,题目真的是明摆着让我们用莫队算法,套用树状数组就可以了. 具体怎么转移呢?如果移动R,那么对区间[l,r]有影响的是R左边的元素,我们只需要看有多少在R左边比a[ ...
- noip模拟赛 蒜头君的坐骑
分析:标准的棋盘dp问题. 如果没有技能,那么就很好做了,相当于传纸条的做法.有了技能的限制,我们就要加上一维表示用了多少次技能,这个时候转移就要用到dfs了,而且不能用填表法,要用刷表法,从当前位置 ...
- noip模拟赛 蒜头君的树
分析:这道题问的是树上整体的答案,当然要从整体上去考虑. 一条边对答案的贡献是这条边一端连接的点的个数*另一端连接的点的个数*边权,可以用一次dfs来统计答案,之后每次更改操作在原答案的基础上增减就好 ...
- noip模拟赛 蒜头君打地鼠
分析:直接一个一个地去暴力枚举分数比较少,我们需要一种比较快的统计一定空间内1的数量,标准做法是前缀和,但是二维前缀和维护的是一个矩形内的值,这个是旋转过的该怎么办?可以把图旋转45°,不过这样比较考 ...
- NOIP模拟赛20161022
NOIP模拟赛2016-10-22 题目名 东风谷早苗 西行寺幽幽子 琪露诺 上白泽慧音 源文件 robot.cpp/c/pas spring.cpp/c/pas iceroad.cpp/c/pas ...
- contesthunter暑假NOIP模拟赛第一场题解
contesthunter暑假NOIP模拟赛#1题解: 第一题:杯具大派送 水题.枚举A,B的公约数即可. #include <algorithm> #include <cmath& ...
- NOIP模拟赛 by hzwer
2015年10月04日NOIP模拟赛 by hzwer (这是小奇=> 小奇挖矿2(mining) [题目背景] 小奇飞船的钻头开启了无限耐久+精准采集模式!这次它要将原矿运到泛光之源的矿 ...
- 大家AK杯 灰天飞雁NOIP模拟赛题解/数据/标程
数据 http://files.cnblogs.com/htfy/data.zip 简要题解 桌球碰撞 纯模拟,注意一开始就在袋口和v=0的情况.v和坐标可以是小数.为保险起见最好用extended/ ...
随机推荐
- bzoj 1572: [Usaco2009 Open]工作安排Job【贪心+堆】
先按照时间顺序加,价值塞进小根堆里,碰到不合法情况就从堆里减去 #include<iostream> #include<cstdio> #include<queue> ...
- bzoj4506: [Usaco2016 Jan]Fort Moo(暴力)
4506: [Usaco2016 Jan]Fort Moo Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 145 Solved: 104[Submi ...
- lodop打印图片
LODOP = getLodop(document.getElementById('LODOP_OB'), document.getElementById('LODOP_EM')); //LODOP. ...
- C#命名空间 using的用法
using的用法: 1. using指令:引入命名空间 这是最常见的用法,例如: using System; using Namespace1.SubNameSpace; 2. using stati ...
- 289 Game of Life 生命的游戏
假设有一个大小为m*n的板子,有m行,n列个细胞.每个细胞有一个初始的状态,死亡或者存活.每个细胞和它的邻居(垂直,水平以及对角线).互动规则如下:1.当前细胞存活时,周围低于2个存活细胞时,该细胞死 ...
- C++(存储类)经典!!
C++变量的存储类别(动态存储.静态存储.自动变量.寄存器变量.外部变量)动态存储方式与静态存储方式 我们已经了解了变量的作用域.作用域是从空间的角度来分析的,分为全局变量和局部变量. 变量还有另一种 ...
- Squid 正向代理
实现通过特定设备对特定的网址访问加速 使用squid 正向代理 实现,区别于反向代理,两者区别的根本在于作为中转的服务器在一个完整的请求中是代表客户端还是代表服务器. 服务端设置 1.安装程序包(推荐 ...
- URL解析-URLComponents
let components = URLComponents(url: fakeUrl, resolvingAgainstBaseURL: false)! http://10.100.140.84/m ...
- N18_二叉树的镜像
题目描述 操作给定的二叉树,将其变换为源二叉树的镜像. 输入描述: 二叉树的镜像定义:源二叉树 8 / \ 6 10 / \ / \ 5 7 9 11 镜像二叉树 8 / \ 10 6 / \ / \ ...
- 12Java Bean
Java Bean JavaBean是一种组件体系结构.实际上,JavaBean就是一个Java类,这个类可以重复地使用.我们可以把JavaBean看成是一个黑盒子,即只需要知道其功能而不必管其内部 ...