atcoder AtCoder Regular Contest 084 D - Small Multiple 最短路

传送门
思路:建立从1开始达到所有数的边,权值为位数和的差。最后dist[0]就是答案,代表最小的位数和能整除K。
相当于建立一个数x到x+1和x*10分别为1和0的边,最后找到最快到达的k的倍数,即答案。
写法1:spfa

#include
using namespace std;
typedef long long LL;
const int MAXN = 1000005;
struct node
{
    int from, to, w;
} G[MAXN];
int dist[MAXN];
int head[MAXN];
bool vis[MAXN];
int cnt;
void add(int u, int v, int w)
{
    G[cnt].to=v;
    G[cnt].w=w;
    G[cnt].from=head[u];
    head[u]=cnt++;
}
void spfa(int s)
{
    memset(vis, false, sizeof(vis));
    queue<int> q;
    while(!q.empty())
        q.pop();
    vis[1]=true;
    q.push(s);
    dist[s]=0;
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        vis[u]=false;
        for(int i=head[u]; ~i; i=G[i].from)
        {
            int v=G[i].to;
            if(dist[v]>dist[u]+G[i].w)
            {
                dist[v]=dist[u]+G[i].w;
                if(!vis[v])
                {
                    vis[v]=true;
                    q.push(v);
                }
            }
        }
    }
}
int main()
{
    int k;
    scanf("%d", &k);
    memset(head, -1, sizeof(head));
    memset(dist, 0x3f,sizeof(dist));
    cnt=0;
    for(int i=0; i1)%k, 1);
        add(i, i*10%k, 0);
    }
    spfa(1);
    printf("%d\n", dist[0]+1);
    return 0;
}

思路二:双端队列
学习一下, 可以重前后插入,然后取队头的数据结构。
首先优先插入x*10,因为权值为0,插在头部。x+1插入尾部。

#include
#include 
#include 
#include 
#include 
using namespace std;
typedef long long LL;
const int MAXN = 100005;
const LL inf = 0x3f3f3f3f;
int main(void){
    int k,v,u;
    cin>>k;
    vector<int> dp(k,1000);
    dp[1] = 0;
    deque<int> deq;
    deq.push_front(1);
    while(v = deq.front()){
        deq.pop_front();
        u = (v*10)%k;
        if(dp[u] > dp[v]){
            dp[u] = dp[v];
            deq.push_front(u);
        }
        u = (v+1)%k;
        if(dp[u] > dp[v]+1){
            dp[u] = dp[v]+1;
            deq.push_back(u);
        }
    }
    cout<1<

你可能感兴趣的:(最短路)