牛客网比赛177 旅游

题目大意

链接:https://www.nowcoder.com/acm/contest/177/B
来源:牛客网

暑假,可怜打算去旅游。

在可怜的计划中,可怜一共打算游玩 nn 个景点,这些景点被 mm 条双向道路联通(即任何两个景点之间都能通过道路直接或者间接到达)。第 ii 条道路的长度为 2i2^i

因为这 nn 个景点中,只有 11 号景点在机场附近,所以可怜想要制定一个从 11 号点出发,沿着道路一路游玩,并在最后回到 11 号点的游览计划。同时因为每一条道路都有不一样的风景,于是可怜想要在这个计划中,经过每一条道路至少一次(只要从一个方向走过就算经过过这条道路)。

令一个游览计划的疲劳度为行走长度的总和(多次经过的边长度被多次计算),可怜想要计算所有满足条件的游览计划中疲劳度的最小值。

100100%的数据1n,m5×1051 ≤ n , m ≤ 5 \times 10^5.

分析

首先,这道题肯定是要把每一条边都走一遍的。

那么,问题就转化成“怎样加入权值最小的边使得这个图是一个欧拉回路”。

怎样的图是欧拉回路呢?

在每个点的度都为偶数的图中,我们就可以从一个点仅遍历所有的边一次回到起点。

问题就变为“如何加入权值最小的边使得这个图每个点的度都为偶数”。

重新审视题面 "第 ii 条道路的长度为 2i2^i。"即我们选了一个i号边加入,即使选上前面所有的边,它们的权值的和都没有这第i号边大。我们考虑贪心的思想,尽量拿少的。

所以这个题就变为“如何选择加入这个图最小生成树的边使得这个图的每个点的度都为偶数。”

我们确定了最小生成树上的边是要选择加入的,那么加哪些可以使得每个点的度都为偶数呢?

我们考虑dfs遍历这棵最小生成树,从每个叶子结点讨论它是否为偶数。若叶子节点不为偶数,那么我们就加一条从此叶子结点到它父亲的边,并且将此叶子结点与其父亲结点的度都加上11

参考代码

//
//  main.cpp
//  B-旅游
//
//  Created by Ted_Tong on 2018/10/14.
//  Copyright © 2018 Ted_Tong. All rights reserved.
//
 
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#define maxm 500010
#define mod 998244353
#define ll long long
using namespace std;
int n,m,cnt_e,cnt_p,root,t,fa[maxm],ind[maxm],head[maxm];
bool vis[maxm];
ll ans;
struct edge{
    int u,v,w;
}edges[maxm*2];//edge存的是原图
bool cmp(edge a,edge b){
    return a.w<b.w;
}
void add_e(int u,int v,int w){
    cnt_e++;
    edges[cnt_e].u=u;
    edges[cnt_e].v=v;
    edges[cnt_e].w=w;
}
struct path{
    int to,nxt,w;
}paths[maxm*2];//path存的是最小生成树
void add_p(int u,int v,int w){
    cnt_p++;
    paths[cnt_p].to=v;
    paths[cnt_p].nxt=head[u];
    paths[cnt_p].w=w;
    head[u]=cnt_p;
}
int find(int x){
    if (fa[x]==x) {
        return fa[x];
    }
    return fa[x]=find(fa[x]);
}
ll quickPower(int b){
    ll res=1,base=2;
    while(b>0){
        if(b&1){
            res*=base;
            res%=mod;
        }
        base*=base;
        base%=mod;
        b>>=1;
    }
    return res;
}
void kruskal(){
    for (int i=1; i<=2*m; i++) {
        int fa_u=find(edges[i].u);
        int fa_v=find(edges[i].v);
        if (fa_u==fa_v) {
            continue;
        }
        add_p(edges[i].u,edges[i].v,edges[i].w);
        add_p(edges[i].v,edges[i].u,edges[i].w);
        fa[fa_v]=fa_u;
        t++;
        if (t==n-1) {
            root=find(fa_u);
            break;
        }
    }
}
void dfs(int pi,int u,int fa){
    for (int i=head[u]; i; i=paths[i].nxt) {
        int v=paths[i].to;
        if (!vis[v]) {
            vis[v]=1;
            dfs(i, v, u);
        }
    }
    if (ind[u]%2==1) {
        ind[u]++;
        ind[fa]++;
        ans=(ans+quickPower(paths[pi].w))%mod;
    }
    return;
}
int main() {
    scanf("%d%d",&n,&m);
    for (int i=1; i<=n; i++) {
        fa[i]=i;
    }
    for (int i=1; i<=m; i++) {
        int u,v;
        scanf("%d%d",&u,&v);
        add_e(u, v, i);
        add_e(v, u, i);
        ind[v]++;
        ind[u]++;
        ans=(ans+quickPower(i))%mod;
    }
    kruskal();
    vis[root]=1;
    dfs(0, root, 0);
    printf("%lld\n",ans);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章