看到这道题我的第一思路是分层图最短路,分层的原因是我们可以将城镇的cost看作每一层的花费,每20件物资看作一层,那么终点的层数就是终点的物资/20,但是我们在SPFA中动态判断层数太麻烦,所以先处理一个分层的数组,每20位为一个区间,然后dis[ed][K[m]]=m->终点第[物资]层的最小值为物资,然后跑分层图,如何更新呢?判断当前要更新的点是城镇还是乡村,如果是城市,就判断当前用来更新的点的dis[u][kth]+1是不是属于kth层,不属于就更新为dis[go][kth+1]=dis[u][kth]+1,是同一层,就更新为同一层;如果是城镇呢?我们发现层数+1,交的物资就要+1,所以判断在同一层的情况下dis[u][kth]+kth是不是属于kth层,属于那么更新dis[go][kth]=dis[u][kth]+kth,不然就更新dis[u][kth]+kth层的最短,更新为dis[go][K[dis[u][kth]+kth]]=dis[u][kth]+kth;,因为跑分层图时我们用的结构体记录每层每个点的信息,所以我们用priority存储,那么就能保证在第一次搜到起点时,就是最优解
--------------------------------------------分割线,上面扯淡,下面说正解------------------------------------------------------
我们也是从ed出发,也是用SPFA,只不过没有分层图那么难转移,我们发现在到达下一个城镇之前,有多少个20,下个城镇就要交多少个,那么每份20都少了1,那么到达下一个城镇后,原来有多少个20,现在就有多少个19,那么我们反推回去,现在有多少个19->dis[u]/19,那么就最少有多少个20->dis[u]/19*20,所以我们要判断至少上一个点要有多少物资,当前点才能被到达,判断条件就是当前有的物资-需要交的物资(go的物资),是不是大于等于要去的城镇的物资(u,我们从go到u,所以反推时我们用u来判断go),因为不足20要补成20,所以我们要+19,因为(一个不大于20的数+19)/20才能保证结果的正确性,也可以直接上取整,判断完了就可以按照正常SPFA更新了
代码(第二种)
//By AcerMo
#include<cmath>
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int M=250;
vector<int>v[M];
int n,m,vis[M],st,ed;
int dis[M],path[M];
inline void add(int x,int y){v[x].push_back(y);v[y].push_back(x);return ;}//连边
inline void clean(){for (int i=0;i<=100;i++) v[i].clear();return ;}//清空
inline int jud(int x,int y)
{
if (x<26) return y-(y+19)/20;//城镇的情况
return y-1;//乡村
}
inline int gets(int x)
{
if (x>25) return dis[x]+1;//乡村
int emm=dis[x]*20/19;//bulabula
while (jud(x,emm)<dis[x]) emm++;
return emm;
}
inline void SPFAS()
{
memset(dis,0x3f,sizeof(dis));
memset(vis,0,sizeof(vis));
dis[ed]=m;queue<int>q;q.push(ed);
while (q.size())
{
int u=q.front();q.pop();vis[u]=0;
for (int i=0;i<v[u].size();i++)
{
int go=v[u][i];
int pay=gets(u);//判断
if (dis[go]>pay)
{
dis[go]=pay;//更新
if (!vis[go])
vis[go]=1,q.push(go);
}
}
}
return ;
}
int main()
{
for (int ti=1;;ti++)
{
scanf("%d",&n);
if (n==-1) return 0;
char a,b;clean();
for (int i=1;i<=n;i++)
cin>>a>>b,add(a-'A',b-'A');
cin>>m>>a>>b;st=a-'A';ed=b-'A';
SPFAS();printf("Case %d: %d\n",ti,dis[st]);
}
return 0;
}