T1

8.11考试差点爆0祭

8.11考试差点爆0祭

8.11考试差点爆0祭

暴力50分:

跑k次没有写错的dij

8.11考试差点爆0祭

看起来似乎是个树

也有可能是森林

也许我们可以把它当树做

据Yousiki说是个入门的树形dp,but我不会

正解:

我们枚举两个距离最近的点的编号

既然两个的int表示不同,就说明它们的二进制表示上至少有一位不同。

假设枚举到第i位,就把这一位为0的点设置为源点,这一位为1的点设置成汇点

然后跑多源多汇最短路

就是设置一个超级源点s,一个超级汇点t

s向每个源点连边权为0的边,所有汇点向t连边权为0的边,然后跑s到t的最短路

stdのcode

#include <queue>
#include <cstdio>
#include <cstring>

template <class cls>
inline cls min(const cls & a, const cls & b) {
    return a < b ? a : b;
}

const int mxn = 100005;
const int mxm = 500005;
const int inf = 0x3f3f3f3f;

int n, m, k;

int points[mxn];

int tot;
int hd[mxn];
int nt[mxm];
int to[mxm];
int vl[mxm];

inline void add_edge(int u, int v, int w) {
    nt[++tot] = hd[u];
    to[tot] = v;
    vl[tot] = w;
    hd[u] = tot;
}

int dis[mxn];

struct data {
    int u, d;

    data(int _u, int _d) :
        u(_u), d(_d) {}
    
    bool operator < (const data & that) const {
        return d > that.d;
    }
};

std::priority_queue<data> heap;

int main() {
    int cas;
    scanf("%d", &cas);
    for (int c = 0; c < cas; ++c) {
        scanf("%d%d%d", &n, &m, &k);
        memset(hd, 0, sizeof(int) * (n + 5)); tot = 0;
        for (int i = 0, u, v, w; i < m; ++i) {
            scanf("%d%d%d", &u, &v, &w);
            add_edge(u, v, w);
            add_edge(v, u, w);
        }
        for (int i = 0; i < k; ++i)
            scanf("%d", points + i);//神仙指针 
        int ans = inf;
        for (int i = 1; i < k; i <<= 1) {
            memset(dis, inf, sizeof(int) * (n + 5));//只memset dis数组的前n+5位 
            for (int j = 0, p; j < k; ++j)//这里对每个地下党按照输入顺序进行编号,然后枚举编号 
                if (p = points[j], (j & i) == 0)//看j的第i位是否是0 
                    heap.push(data(p, dis[p] = 0));//把第i位为0的设置成了源点 
            while (!heap.empty()) {
                int u = heap.top().u;
                int d = heap.top().d;
                heap.pop();
                if (dis[u] != d)
                    continue;
                for (int e = hd[u], v, w; e; e = nt[e])
                    if (v = to[e], w = vl[e], dis[v] > d + w)
                        heap.push(data(v, dis[v] = d + w));
            }
            for (int j = 0, p; j < k; ++j)
                if (p = points[j], (j & i) != 0)
                    ans = min(ans, dis[p]);
        }
        printf("%d\n", ans == inf ? -1 : ans);
    }
    return 0;
}
神奇的代码

相关文章:

  • 2021-08-18
  • 2022-01-08
  • 2021-06-04
  • 2019-08-12
  • 2021-04-13
  • 2019-07-08
  • 2021-11-05
  • 2021-06-18
猜你喜欢
  • 2021-09-24
  • 2021-08-27
  • 2021-11-23
  • 2021-09-21
  • 2022-02-17
  • 2021-04-24
  • 2021-08-08
相关资源
相似解决方案