NOIP模拟赛-货物运输(Toll)

题目在这里

看到这道题我的第一思路是分层图最短路,分层的原因是我们可以将城镇的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;
}

猜你喜欢

转载自blog.csdn.net/ACerAndAKer/article/details/80930066