D. Edge Deletion

该博客讨论了一种图论问题,即如何在保持从节点1到其他节点最短路径不变的前提下,最多保留k条边。当k大于等于n-1时,只需保留最短路径上的边;当k小于n-1时,需要删除最短路径树上的深层边。解决方案是使用Dijkstra算法找到最短路径树,然后通过深度优先搜索和广度优先搜索进行边的选取和记录。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

传送门

题 意 : 给 定 一 张 无 向 图 , 问 最 多 保 留 k 条 边 , 使 得 有 1 到 其 余 点 题意:给定一张无向图,问最多保留k条边,使得有1到其余点 k使1

的 最 短 路 不 变 的 点 数 最 多 。 的最短路不变的点数最多。

分 析 : 最 短 路 径 树 , 很 明 显 , 当 k ≥ n − 1 时 , 我 们 只 需 要 保 分析:最短路径树,很明显,当{k}\geq{n-1}时,我们只需要保 kn1
留 最 短 路 径 上 的 边 即 可 留最短路径上的边即可

当 k ≤ n − 1 时 , 需 要 删 除 最 短 路 径 树 上 的 一 些 边 当k\leq{n-1}时,需要删除最短路径树上的一些边 kn1

且 这 些 边 为 最 深 层 的 边 且这些边为最深层的边

在 跑 最 短 路 的 同 时 利 用 p r e 记 录 每 个 点 的 前 驱 , 然 后 重 新 建 出 在跑最短路的同时利用pre记录每个点的前驱,然后重新建出 pre

最 短 路 径 树 , 最 后 b f s 记 录 边 即 可 最短路径树,最后bfs记录边即可 bfs

c o d e : code: code:

#include <set>
#include <map>
#include <list>
#include <cmath>
#include <stack>
#include <queue>
#include <string>
#include <bitset>
#include <vector>
#include<cstring>
#include <stdio.h>
#include <iomanip>
#include <iostream>
#include <algorithm>
using namespace std;
#define endl "\n"
#define ll long long
#define Mp make_pair
#define INF 0x3f3f3f3f
#define Pair pair<int,int>
typedef unsigned long long ull;
#define IO ios::sync_with_stdio(false);
const int N = 2e6+5;
const int maxn = 3e5+5;

#define int long long

vector<Pair>e[maxn];
int pre[maxn];
int dis[maxn],vis[maxn];
void Dij(int s)
{
    memset(dis,INF,sizeof dis);
    priority_queue<Pair,vector<Pair>,greater<Pair>>q;
    q.push({0,s});
    dis[s]=0;
    while(!q.empty())
    {
        int x=q.top().second; q.pop();
        if(vis[x]) continue; vis[x]=true;
        for(auto v:e[x])
        {
            int y=v.first,w=v.second;
            if(dis[y]>dis[x]+w){
                dis[y]=dis[x]+w;
                pre[y]=x;
                if(!vis[y]) q.push({dis[y],y});
            }
        }
    }
}

int n,m,k;
bool use[maxn];
vector<int>ee[N],ans;
map<int,map<int,int>>mp,p;

void dfs(int x)
{
    int y=pre[x];
    if(y==-1||p[x][y]==1) return;
    p[x][y]=p[y][x]=1;
    ee[y].push_back(x);
    dfs(y);
}
void bfs(int s)
{
    int cnt=0;
    queue<int>q; q.push(s);

    while (!q.empty())
    {
        int x=q.front(); q.pop();
        for(auto y:ee[x])
        {
            if(cnt<k&&!use[mp[x][y]])
                ans.push_back(mp[x][y]),use[mp[x][y]]=true,cnt++;
            if(cnt==k) break;
            q.push(y);
        }
        if(cnt==k) break;
    }
    cout<<ans.size()<<endl;
    for(auto id:ans) cout<<id<<" ";
    cout<<endl;
}
void solve()
{
    cin>>n>>m>>k;
    memset(pre,-1,sizeof pre);
    k=min(k,n-1);
    for(int i=1;i<=m;i++){
        int u,v,w; cin>>u>>v>>w;
        e[u].push_back({v,w});
        e[v].push_back({u,w});
        mp[u][v]=i;
        mp[v][u]=i;
    }
    Dij(1);
    for(int i=1;i<=n;i++) dfs(i);
    bfs(1);
}
signed main()
{
//            freopen("5.in","r",stdin);
//            freopen("5.out","w",stdout);
    IO;
//    int T;cin>>T; while (T--)
    solve();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值