ICPC Arab Collegiate Programming Contest 2013训练赛
Problem K. Mario Kart
题意概述:
一条路上有n个车站,你有m个金币,金币有各自的费用c和价值v,可以通过金币在车站间移动,每次移动要选择一些金币,总成本不能超过L,其价值和必须刚好等于abs(i-j),问从1号站移动到n号站最少移动多少次.
输入:
测试总量N,站点数目n,金币数目m,限制l。
一下m行为费用c和价值v。
一道经典的背包+dijsktra题目,dijkstra部分完全不需要改变,但是数组存储的过程需要些技巧。
首先定义动规数组dp,记录不同相隔距离间的最小花费。
//开始dp全部为极大值
for(int i=1;i<=m;++i)//遍历金币数
{
for(int j=p[n]-p[1];j>=v[i];--j)//从最大距离到当前可能的最小距离遍历
dp[j]=min(dp[j],dp[j-v[i]]+c[i]); //动规保存每个距离下的最小花费
}
然后创建map数组,如果dp[p[j]-p[i]]]<=l,说明从i
到j有金币可以支撑其到达并且还在限制l之内,那么将map数组的值设为1,说明一步可以达到,否则的话数组的值为极大值。
void build_map()
{
for(int i=1; i<=n; ++i)
{
for(int j=1; j<=n; ++j)
{
if(p[i]==p[j])
mp[i][j]=0;
else
mp[i][j]=1e9+7;
}
}
for(int i=1; i<=n; ++i)
{
for(int j=i+1; j<=n; ++j)
{
if(dp[p[j]-p[i]]<=l)
mp[i][j]=mp[j][i]=1;
}
}
}
最后直接通过最短路径dijsktra求得从1到n的最短距离即可。
开始看到题的时候想到是最短路径了,但是并没有直接给出他们的距离。那么难点就在于如何得出不同站点之间的距离。
所以我们先脱离站点,通过dp求出不同距离对应的最小花费,然后构建数组,两次循环遍历站点,求得dp[不同站点之间的距离]如果<=l,说明可以一步到达,就将数组的值设为1,如果非的话,直接就是初始值极大值。
通过二维数组直接最短路径算法求出1-n的最短花费,如果不满足的话输出-1。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1010;
int n, m, l;
int dp[maxn], dis[maxn], vis[maxn], ma[maxn][maxn];
int p[maxn], c[maxn], v[maxn];
int mod = 1e9 + 7;
void build()
{
for(int i=1; i<=n; i++){
for(int j=1; j<=n; j++){
if(p[i]==p[j])
ma[i][j]=0;
else
ma[i][j]=mod;
}
}
for(int i=1; i<=n; i++){
for(int j=i+1; j<=n; j++){
if(dp[p[j]-p[i]]<=l){
ma[i][j]=1;
ma[j][i]=1;
}
}
}
}
int dijskstra(int u)
{
memset(vis, 0, sizeof(vis));
for(int i=1; i<=n; i++){
dis[i]=ma[u][i];
}
dis[u]=0;
vis[u]=1;
for(int i=1; i<n; i++){
int minn=mod, temp;
for(int j=1; j<=n; j++){
if(!vis[j]&&dis[j]<minn){
minn=dis[j];
temp=j;
}
}
vis[temp]=1;
for(int j=1; j<=n; j++){
if(!vis[j] && dis[j]>ma[temp][j]+dis[temp])
dis[j]=ma[temp][j]+dis[temp];
}
}
if(dis[n]==mod) return -1;
return dis[n];
}
int main()
{
int N;
scanf("%d",&N);
while(N--){
scanf("%d %d %d",&n, &m, &l);
for(int i=1; i<=n; i++){
scanf("%d",&p[i]);
}
sort(p+1, p+n+1);
for(int i=1; i<=m; i++){
scanf("%d %d",&c[i], &v[i]);
}
for(int i=1; i<maxn; i++){
dp[i]=mod;
}
dp[0]=0;
for(int i=1; i<=m; i++){
for(int j=p[n]-p[1]; j>=v[i]; j--)
dp[j]=min(dp[j],dp[j-v[i]]+c[i]);
}
build();
printf("%d\n",dijskstra(1));
}
return 0;
}