专栏文章

题解:P12593 沉石鱼惊旋

P12593题解参与者 3已保存评论 3

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
3 条
当前快照
1 份
快照标识符
@mip7lr7m
此快照首次捕获于
2025/12/03 07:28
3 个月前
此快照最后确认于
2025/12/03 07:28
3 个月前
查看原文

Solution

今天比赛挂分了,写篇题解弥补一下吧。
这道题要求我们找到一个删除图中所有节点的顺序,使得删除过程中的总代价最小。每次删除一个节点时,代价是与该节点相连且未被删除的边的权值之和乘以这些边的数量。
开题时先看数据范围。我们发现 n8n≤8,所以我们可以枚举全排列枚举删除顺序。使用打删除标记遍历每一条边来模拟题意。
至于枚举全排列可以使用 next_permutation 生成所有节点的排列顺序,每一种排列代表一种可能的删除顺序。,不会用的也可以用 DFS 搜索(同理)。
模拟删除的过程可以用维护一个数组 dd 来记录哪些节点已经被删除。
对于当前要删除的节点 uu,统计与 uu 相连且未被删除的边的数量 cntcnt 和这些边的权值之和 ss
再计算本次操作的代价 cnt×scnt \times s,并累加到总代价中。
然后标记节点 uu 为已删除。
最后在所有排列对应的总代价中,记录最小的那个。
本题解使用数组实现,没学过树的同学可以看看。
code
CPP
#include<bits/stdc++.h>
using namespace std;
long long n,m,a[103][103],b[103][103],c[130],x,y,z,e=1e18;
bool d[103];
int main() 
{
    cin>>n>>m;
    for(int i=0;i<m;i++) 
    {
        cin>>x>>y>>z;
        a[x][y]=a[y][x]=1;//
标记边是否存在
        b[x][y]=b[y][x]=z;//存储边的权值
    }
    for(int i=0;i<n;i++) 
        c[i]=i+1;//初始化排列数组
    while(next_permutation(c,c+n))//生成下一个全排列
    {
        for(int i=1;i<=n;i++) 
            d[i]=false;//重置删除标记
        long long summ=0;
        for(int i=0;i<n;i++)
        {
            long long u=c[i],cnt=0,s=0;
            for(int j=1;j<=n;j++) 
                if(a[u][j]&&!d[j]) cnt++,s+=b[u][j];//统计边数和权值和
            summ+=cnt*s;//累加代价
            d[u]=true;//标记为已删除
        }
        e=min(summ,e);//更新最小代价
    } 
    cout<<e;
    return 0;
}

评论

3 条评论,欢迎与作者交流。

正在加载评论...