Codeforces 1209F. Koala and Notebook

传送门

考虑到达某个点时的数长度要尽量短,那么可以把边长看成此边十进制下的位数

那么对于最终答案我们只要考虑最短路 $DAG$ 上的情况

又发现其实边长都很小,所以可以暴力拆边,把边权都拆成 $1$,这样就可以 $BFS$ 了

考虑最优情况,对于 $BFS$ 时同一层的点,要扩展到下一层,我们肯定要优先让边的数字为 $1$ 的边先走

然后剩下走 $1$ 到不了的点我们再试着走 $2$,然后 $3$ ,$4$ ... 这样下去,这样到达下一层以后每个点的路径才是最优的

所以我们就要一些比较神仙的操作来实现这个过程...我可能也讲不清楚了,自己看代码吧

代码参考:wxhtxdy

 

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<vector>
using namespace std;
typedef long long ll;
inline int read()
{
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
    while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
    return x*f;
}
const int N=1e6+7,mo=1e9+7;
int n,m,tot,ans[N];
vector <int> e,V[N][10],Q[N];//V是边,Q是BFS的队列,队列为啥是vector等等就知道了...
bool vis[N];
int main()
{
    n=read(),m=read(); int a,b;
    tot=n;
    for(int i=1;i<=m;i++)
    {
        a=read(),b=read(); int t=i,c; e.clear();
        while(t) c=t%10,t/=10,e.push_back(c);
        reverse(e.begin(),e.end()); int pre=a,len=e.size();
        for(int j=0;j<len;j++)//拆点
        {
            int np=(j==len-1 ? b : ++tot);
            V[pre][e[j]].push_back(np),pre=np;
        }
        pre=b;
        for(int j=0;j<len;j++)//无向图两边都要拆
        {
            int np=(j==len-1 ? a : ++tot);
            V[pre][e[j]].push_back(np),pre=np;
        }
    }
    int T=0; Q[++T].push_back(1); vis[1]=1;
    for(int i=1;i<=T;i++)
        for(int j=0;j<=9;j++)//优先走数字小的
        {
            bool flag=0;
            for(auto x: Q[i])//对于同一个i,Q[i]中的点的ans都是一样的
                for(auto v: V[x][j])//走到下一层
                {
                    if(vis[v]) continue;//走过就不用再走了
                    vis[v]=flag=1; Q[T+1].push_back(v);
                    ans[v]=(10ll*ans[x]+j)%mo;//更新答案
                }
            if(flag) T++;
        }
    for(int i=2;i<=n;i++) printf("%d\n",ans[i]);
    return 0;
}

 

posted @ 2019-09-16 12:01  LLTYYC  阅读(384)  评论(0编辑  收藏  举报