牛客網比賽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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章