淦。。。。 2025-11-02 21:01 采纳率: 33.3%
浏览 13
已结题

关于#测试数据#的问题,如何解决?(相关搜索:小根堆)

题目:csp-s2025T2

P14362 [CSP-S 2025] 道路修复 / road(民间数据)

题目背景

由于评测机性能差异,本题时限提升 1 秒。

测试数据未经过强度检验,可能存在错误做法获得较高分数,仅供参考。

题目描述

C 国的交通系统由 $n$ 座城市与 $m$ 条连接两座城市的双向道路构成,第 $i$ ($1 \leq i \leq m$) 条道路连接城市 $u_i$ 和 $v_i$。任意两座城市都能通过若干条道路相互到达。

然而,近期由于一场大地震,所有 $m$ 条道路都被破坏了,修复第 $i$ ($1 \leq i \leq m$) 条道路的费用为 $w_i$。与此同时,C 国还有 $k$ 个准备进行城市化改造的乡镇。对于第 $j$ ($1 \leq j \leq k$) 个乡镇,C 国对其进行城市化改造的费用为 $c_j$。在城市化改造完第 $j$ ($1 \leq j \leq k$) 个乡镇后,可以在这个乡镇与原来的 $n$ 座城市间建造若干条道路,其中在它与第 $i$ ($1 \leq i \leq n$) 座城市间建造一条道路的费用为 $a_{j,i}$。C 国可以在这 $k$ 个乡镇中选择任意多个进行城市化改造,也可以不选择任何乡镇进行城市化改造。

为尽快恢复城市间的交通,C 国政$ $府希望以最低的费用将原有的 $n$ 座城市两两连通,也即任意两座原有的城市都能通过若干条修复或新建造的道路相互到达。你需要帮助他们求出,将原有的 $n$ 座城市两两连通的最小费用。

输入格式

输入的第一行包含三个非负整数 $n, m, k$,分别表示原有的城市数量、道路数量和准备进行城市化改造的乡镇数量。

输入的第 $i+1$ ($1 \leq i \leq m$) 行包含三个非负整数 $u_i, v_i, w_i$,表示第 $i$ 条道路连接的两座城市与修复该道路的费用。

输入的第 $j+m+1$ ($1 \leq j \leq k$) 行包含 $n+1$ 个非负整数 $c_j, a_{j,1}, a_{j,2}, \ldots, a_{j,n}$,分别表示将第 $j$ 个乡镇进行城市化改造的费用与在该乡镇与原有的城市间建造道路的费用。

输出格式

输出一行一个非负整数,表示将原有的 $n$ 座城市两两连通的最小费用。

输入输出样例 #1

输入 #1

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

输出 #1

13

说明/提示

【样例 1 解释】

C 国政$ $府可以选择修复第 $3$ 条和第 $4$ 条道路,然后将第 $1$ 个乡镇进行城市化改造,并建造它与第 $1,3$ 座城市间的道路,总费用为 $5 + 4 + 1 + 1 + 2 = 13$。可以证明,不存在比 $13$ 更小的费用能使原有的 $4$ 座城市两两连通。

【样例 2】

见选手目录下的 $road/road2.in$ 与 $road/road2.ans$。

该样例满足测试点 $11,12$ 的约束条件。

【样例 3】

见选手目录下的 $road/road3.in$ 与 $road/road3.ans$。

该样例满足测试点 $13,14$ 的约束条件。

【样例 4】

见选手目录下的 $road/road4.in$ 与 $road/road4.ans$。

该样例满足测试点 $15,16$ 的约束条件。

【数据范围】

对于所有测试数据,保证:

  • $1 \leq n \leq 10^4$,$1 \leq m \leq 10^6$,$0 \leq k \leq 10$;
  • 对于所有 $1 \leq i \leq m$,均有 $1 \leq u_i, v_i \leq n$, $u_i \neq v_i$ 且 $0 \leq w_i \leq 10^9$;
  • 对于所有 $1 \leq j \leq k$,均有 $0 \leq c_j \leq 10^9$;
  • 对于所有 $1 \leq j \leq k$,$1 \leq i \leq n$, 均有 $0 \leq a_{j,i} \leq 10^9$;
  • 任意两座原有的城市都能通过若干条原有的道路相互到达。

::cute-table{tuack}

测试点编号$n \leq$$m \leq$$k \leq$特殊性质
$1 \sim 4$$10^4$$10^6$$0$
$5, 6$$10^3$$10^5$$5$A
$7, 8$^^^
$9, 10$^$10^6$^A
$11, 12$^^^
$13, 14$^^$10$A
$15, 16$^^^
$17, 18$$10^4$^$5$A
$19, 20$^^^
$21 \sim 25$^^$10$^

特殊性质 A:对于所有 $1 \leq j \leq k$,均有 $c_j = 0$ 且均存在 $1 \leq i \leq n$ 满足 $a_{j,i} = 0$。

思路:

kurskal,用小根堆给每条边排序,把乡镇连接的城市i,j看成一条i,j的路,边权为a_ik+c_k+a_kj。并且标记需要乡镇k这个中转站,加入堆中。跑kurskal时如果遇到需要中转站的边那就把乡镇城市化,并且把所有连边减去c_k当正常边加入到堆中。

代码


#include<bits/stdc++.h>
using namespace std;
int father[10005],n,m,k,c[15];
long long ans;
vector<long long>s[15];

struct edge{
    int u,v;
    long long w;
    int p;
    bool operator<(const edge &it)const{
        return w>it.w;
    }
};
priority_queue<edge> q;
int find(int x){
    if(x==father[x])return x;
    return father[x]=find(father[x]);
}
void unionn(int x,int y){
    father[find(y)]=find(x);
    return;
}
void kruskal(){
    int kk=0;
    while(!q.empty()){
        int u=q.top().u;
        int v=q.top().v;
        long long w=q.top().w;
        int p=q.top().p;
        q.pop();
        if(find(u)!=find(v)){
            if(p>0){
                for(int i=1;i<n;i++)
                for(int j=i+1;j<=n;j++)q.push({i,j,s[p][i-1]+s[p][j-1],0});
            }
            ans+=w;
            unionn(u,v);
            kk++;
        }
        if(kk==n-1)break;
    }
    return;
}
int main(){
    freopen("road.in","r",stdin);
    freopen("road.out","w",stdout);
    scanf("%d %d %d",&n,&m,&k);
    for(int i=1;i<=n;i++)father[i]=i;
    for(int i=1;i<=m;i++){
        int u,v;
        long long w;
        scanf("%d %d %lld",&u,&v,&w);
        q.push({u,v,w,0});
    }
    for(int i=1;i<=k;i++){
        cin>>c[i];
        for(int j=1;j<=n;j++){
            long long w;
            scanf("%lld",&w);
            s[i].push_back(w);
        }
        for(int j=1;j<n;j++)
        for(int k=j+1;k<=n;k++)
        if(j!=k){
            if(c[i]==0) q.push({j,k,s[i][j-1]+s[i][k-1],0});
            else q.push({j,k,s[i][j-1]+c[i]+s[i][k-1],i});
        }
    }
    kruskal();
    cout<<ans;
    return 0;
}

求问正确性

  • 写回答

4条回答 默认 最新

  • 2401_84079994 2025-11-03 11:20
    关注

    Based on my understanding, it is like building a group with connecting mandatory members and optional members (eg member id for sample #1, 1,2,3,4 is mandatory and 5,6 is optional). Using brute force approach now you can construct the group in different ways by picking its members one by one. So start with 1-6, try to connect to higher id (avoid duplicate combinations), until all mandatory members are connected. Finally return the one with lowest cost. You need to pay attention for connections from id 5/6 to id1-4 (allowed, but not directly from 4 to 3 or similar allowed to avoid duplicate combinations. Or ignore this for time being and focus on how to get the correct answer). The critical logic is to connect to all mandatory members one by one in all possible ways. You may construct a matrix first containing all valid connections and then start the grouping process.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(3条)

报告相同问题?

问题事件

  • 系统已结题 11月12日
  • 已采纳回答 11月4日
  • 创建了问题 11月2日