- Description
题目背景: 尊者神高达进入了基三的世界,作为一个 mmorpg 做任务是必不可少的,然而跑地图却令人十分不爽。好在基三可以使用轻功,但是尊者神高达有些手残,他决定用梅花桩练习轻功。 题目描述: 一共有 n 个木桩,要求从起点(0)开始,经过所有梅花桩,恰好到达终点 n,尊者神高达一共会 k 种门派的轻功,不同门派的轻功经过的梅花桩数不同,花费时间也不同。但是尊者神高达一次只能使用一种轻功,当他使用别的门派的轻功时,需要花费 W 秒切换(开始时可以是任意门派,不需要更换时间)。由于尊者神高达手残,所以经过某些梅花桩(包括起点和终点)时他不能使用一些门派的轻功。尊者神高达想知道他最快多久能到达终点如果无解则输出-1。
- Input
第一行 n,k,W 接下来 k 行,每行为 ai 和 wi 代表第 i 种轻功花费 vi 秒经过 ai 个木桩。 接下来一行 Q 为限制条件数量。 接下来 Q 行,每行为 xi 和 ki 代表第 xi 个梅花桩不能使用第 ki 种门派的轻功经过。
- Output
一行答案即所需最短时间。
- Sample Input
Sample Input1:
6 2 5
1 1
3 10
2
1 1
2 1
Sample Input2:
6 2 5
1 1
3 10
0
- Sample Output
Sample Output1:
18
样例解释 1: 先用第二种轻功花费 10 秒到 3,再用 5 秒切换到第一种轻功,最后再用 3 秒时间到 6.一共花费 10+5+3=18 秒
Sample Output2:
6
样例解释 2:
直接花费 6 秒到 6;
- Data Constraint
20%的数据 n<=20,k<=10,Q<=200;
对于另外 20%的数据 W=0
对于另外 20%的数据 Q=0
所以数据满足 n<=500,k<=100,Q<=50000,vi<=1e7;
保证数据合法
- 题目分析
这道题我们看到这个数据范围发现好像并不大,然后又有多种选择,让我不免想到了DP
我们设f[当前位置][跳到这个位置的功法]为最低代价
我们用一个last数组保存上一次禁止这种功法的位置(这里用链式前向星讲位置向禁止的功法连一条边)
然后可以通过last和当前位置判断出当前位置是否可以用某种功法跳过来
下面给出代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll INF = 1e15;
ll n,k,w,q;
struct xx
{
ll waste;
ll can;
}a[105];
struct xxx
{
ll next;
ll to;
}ban[50005];
ll f[505][105];
ll cnt,head[505],last[105];
void add(int u,int v)
{
ban[++cnt].next = head[u];
ban[cnt].to = v;
head[u] = cnt;
return;
}
void in(ll &x)
{
x = 0;
ll f = 1;
char c = getchar();
while (c < '0' || c > '9')
{
if (c == '-') f = -1;
c = getchar();
}
while (c >= '0' && c <= '9')
{
x = x * 10 + c - '0';
c = getchar();
}
x *= f;
return;
}
void out(ll x)
{
if (x < 0)
{
putchar('-');
x = -x;
}
if (x > 9)
{
out(x / 10);
}
putchar(x % 10 + '0');
}
int main()
{
// freopen("qinggong.in","r",stdin);
// freopen("qinggong.out","w",stdout);
for (int i = 0; i <= 502; i++)
{
for (int j = 0; j <= 102; j++)
{
f[i][j] = INF;
}
}
in(n);
in(k);
in(w);
for (int i = 1; i <= k; i++)
{
in(a[i].can);
in(a[i].waste);
}
in(q);
for (int i = 1; i <= q; i++)
{
ll pos,cant;
in(pos);
in(cant);
add(pos,cant);
}
for (int i = 1; i <= k; i++)
{
f[0][i] = 0;
}
for (int pos = 1; pos <= n; pos++)
{
for (int i = head[pos]; i; i = ban[i].next)
{
last[ban[i].to] = pos;
}
for (int type = 1; type <= k; type++)
{
if (last[type])
{
if (pos - last[type] > a[type].can)
{
for (int i = 1; i <= k; i++)
{
if (f[pos-a[type].can][i] == INF) continue;
if (i == type)
{
f[pos][type] = min(f[pos][type],f[pos-a[type].can][i]+a[type].waste);
}
f[pos][type] = min(f[pos][type],f[pos-a[type].can][i]+a[type].waste+w);
}
}
}
else
{
if (pos == a[type].can)
{
for (int i = 1; i <= k; i++)
{
f[pos][type] = min(f[pos][type],f[pos-a[type].can][i]+a[type].waste);
}
}
else if (pos > a[type].can)
{
for (int i = 1; i <= k; i++)
{
if (f[pos-a[type].can][i] == INF) continue;
if (i == type)
{
f[pos][type] = min(f[pos][type],f[pos-a[type].can][i]+a[type].waste);
}
f[pos][type] = min(f[pos][type],f[pos-a[type].can][i]+a[type].waste+w);
}
}
}
}
}
ll ans = INF;
for (int i = 1; i <= k; i++)
{
if (ans > f[n][i]) ans = f[n][i];
}
if (ans == INF) ans = -1;
out(ans);
return 0;
}