列表

详情


NC231655. 俺的图图呢

描述

你有一个n个点m条边的带权无向图(不一定连通),现在有k个关键点,请设计一种方案,将这些点分成若干个大小大于1的集合S_i,且任意一个关键点至少要在某一个集合中,那么可以定义集合S_i的价值:

1. 将S_i中的所有元素按某一方式排列得到序列.
2. 对于P_j,需要在原图中找到一条从的**简单路径**(即不经过重复点的路径),同时也要找一条从P_1的简单路径,并记录路径上每条边的经过次数。
3. 集合S_i的价值val_iw_e为该边边权,即经过这条边奇数次,其贡献为w_e,否则为0)。

如果这种方案划分出了x个集合,那么该方案的花费是.

求花费最小的方案的花费。

保证这k个关键点中,每一个点至少可以通向另外一个点。

输入描述

第一行三个整数n,m,k,含义如题面所述。
第二行k个整数,表示k个关键点。
接下来m行,每行三个整数x,y,w,表示一条在结点xy之间,边权为w的无向边。
,没有自环和重边)

输出描述

一个整数,即题目中所求的最小花费。

示例1

输入:

8 7 6
1 5 4 6 8 7
2 5 3
1 4 4
5 3 1
6 3 8
3 7 5
2 8 9
2 3 6

输出:

2

说明:


可分成两个集合S_1 = \{5,6,7,8\},S_2 = \{1,4\}.在集合S_1中,可以构造序列P_1 = \{6,7,5,8\},选择路径6\to 3\to 7,7\to 3\to 5,5\to 3\to 2\to 8,8\to2\to 3\to 6,这样每条边都走了两次,因此val_1 = 0;在集合S_2中,构造序列P_2 = \{1,4\},选择路径1\to 4,4\to 1,这样这条边也走了两次,因此val_2=0.那么答案就是2+0+0=2,可以证明,这是所求的最小值。

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++(g++ 7.5.0) 解法, 执行用时: 214ms, 内存消耗: 7076K, 提交时间: 2022-11-22 12:05:43

#include<bits/stdc++.h>
using namespace std;
vector<int> e[100010];
int vis[100010], a[100010];
int n, m, k;
void dfs(int u)
{
    vis[u] = 1;
    for (int v : e[u]) {
        if (!vis[v]) dfs(v);
    }
}

int main()
{
    cin >> n >> m >> k;
    for (int i = 1; i <= k; i++) cin >> a[i];
    for (int i = 1; i <= m; i++) {
        int u, v, d;
        cin >> u >> v >> d;
        e[u].push_back(v);
        e[v].push_back(u);
    }
    int res = 0;
    for (int i = 1; i <= k; i++) {
        if (!vis[a[i]]) {
            res++;
            dfs(a[i]);
        }
    }
    cout << res;
    return 0;
}

C++ 解法, 执行用时: 66ms, 内存消耗: 1016K, 提交时间: 2021-12-13 17:44:19

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int n,m,k,f[N],s[N];
bool vs[N];
int find(int u){
    return (u==f[u])?u:(f[u]=find(f[u]));
}
int main(){
    cin>>n>>m>>k;
    for(int i=1;i<=k;i++) scanf("%d",&s[i]);
    for(int i=1;i<=n;i++) f[i]=i;
    while(m--){
        int u,v,w;
        scanf("%d%d%d",&u,&v,&w);
        u=find(u); v=find(v);
        f[v]=u;
    }
    //for(int i=1;i<=n;i++) cout<<find(i)<<endl;
    int c=0;
    for(int i=1;i<=k;i++) if(!vs[find(s[i])]){
        vs[find(s[i])]=1; c++;
    }
    cout<<c<<endl;
}

上一题