【 Educational Codeforces Round 54 (Rated for Div. 2) D. Edge Deletion】dij+思维

35 篇文章 1 订阅
3 篇文章 0 订阅

D. Edge Deletion

题意

在 一 个 n 个 点 m 条 边 的 无 向 图 中 起 点 为 1 , 设 初 始 到 达 第 i 个 点 的 最 短 距 离 为 d [ i ] 在一个n个点m条边的无向图中起点为1,设初始到达第i个点的最短距离为d[i] nm1id[i]
现 在 要 求 在 图 上 删 边 , 使 剩 下 的 边 不 超 过 k 条 , 并 让 尽 量 多 的 点 d [ i ] 与 之 前 相 等 现在要求在图上删边,使剩下的边不超过k条,并让尽量多的点d[i]与之前相等 使kd[i]

做法

我 们 发 现 d i j 跑 出 来 的 图 最 终 每 个 点 只 有 一 个 前 驱 我们发现dij跑出来的图最终每个点只有一个前驱 dij
那 么 这 就 是 一 棵 树 , 在 树 上 从 根 节 点 往 下 保 存 边 不 会 影 响 子 孙 的 d 那么这就是一棵树,在树上从根节点往下保存边不会影响子孙的d d
所 以 跑 出 d i j 树 之 后 从 根 往 下 保 留 k 条 边 就 可 以 了 。 所以跑出dij树之后从根往下保留k条边就可以了。 dijk

坑点

最 短 路 用 d i j 不 要 用 s p f a 最短路用dij不要用spfa dijspfa
边 权 和 会 超 过 l o n g   l o n g 边权和会超过long \ long long long

代码

#include<iostream>
#include<math.h>
#include<stdio.h>
#include<algorithm>
#include<queue>
#include<map>
#include<bitset>
#include<stack>
#include<set>
#include<vector>
#include <time.h>
#include<string.h>
using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef double db;
typedef pair <int, int> pii;
typedef pair <ll, ll> pll;
typedef pair <ll, int> pli;
typedef pair <db, db> pdd;

const int maxn = 3e5+5;
const int Mod=1000000007;
const int INF = 0x3f3f3f3f;
const ll LL_INF = 0x3f3f3f3f3f3f3f3f;
const double e=exp(1);
const db PI = acos(-1);
const db ERR = 1e-10;

#define Se second
#define Fi first
#define pb push_back
#define dbg(x) cout<<#x<<" = "<< (x)<< endl
#define dbg2(x1,x2) cout<<#x1<<" = "<<x1<<" "<<#x2<<" = "<<x2<<endl
#define dbg3(x1,x2,x3) cout<<#x1<<" = "<<x1<<" "<<#x2<<" = "<<x2<<" "<<#x3<<" = "<<x3<<endl

typedef long long ll;
#define maxm 600005
#define maxn 300005
#define inf 0x3f3f3f3f3f3f3f3f
struct P
{
    int to;
    ll cost;
    bool operator < (const P & a) const
    {
        return cost>a.cost;
    }
};
struct node
{
    int to;
    ll val;
    int nxt;
    int id;
    int s;
}edge[maxm];
int head[maxn],tot;//head和tot记得重置,head重置为-1
int n,m;//点数,边数,不要再main里面重新定义
bool vis[maxn];//每次在dij里面初始化为0
ll dis[maxn];//根据题意初始化为inf可能int可能longlong
void addedge(int x,int y,ll val,int id)
{
    edge[tot].to=y;
    edge[tot].val=val;
    edge[tot].nxt=head[x];
    edge[tot].id=id;
    head[x]=tot++;
}
int pre[maxn],prem[maxn];
int vv[maxn];
void Dijkstra(int s)
{
    memset(vis,0,sizeof(vis));
    fill(dis,dis+n+2,inf);
    dis[s]=0;
    priority_queue<P>q;
    q.push(P{s,0});
    while(!q.empty())
    {
        P p1=q.top();q.pop();
        int u=p1.to;
        if(vis[u])continue;
        vis[u]=1;
        for(int i=head[u];i+1;i=edge[i].nxt)
        {
            int v=edge[i].to;
            if(vis[v])continue;
            if(dis[v]>dis[u]+edge[i].val)
            {
                pre[v]=u;//记录每个点的点前驱
                prem[v]=edge[i].id;//记录每个点的边前驱
                dis[v]=dis[u]+edge[i].val;
                q.push(P{v,dis[v]});
            }
        }
    }
}
vector<pii> G[maxn];
vector<int> ans;
int ind[maxn];
int cc,k;
void dfs(int st)
{
    if(cc==k) return ;
    for(int i=0;i<G[st].size();i++)
    {
        cc++;
        ans.push_back(G[st][i].Se);
        if(cc==k) return;
        dfs(G[st][i].Fi);
        if(cc==k) return ;
    }
}
int main()
{
   int u,v;
   ll w;
   memset(head,-1,sizeof(head));
   scanf("%d%d%d",&n,&m,&k);
   for(int i=1;i<=m;i++)
   {
        scanf("%d%d%lld",&u,&v,&w);
        addedge(u,v,w,i);
        addedge(v,u,w,i);
   }
   Dijkstra(1);
   if(k>=n-1)
   {
       printf("%d\n",n-1);
       for(int i=2;i<=n;i++)
       {
           printf("%d ",prem[i]);
       }
   }
   else
   {
       int re=n-1;
       for(int i=2;i<=n;i++)
       {
          G[pre[i]].push_back(pii(i,prem[i]));//重新根据前驱生成一棵树
       }
        cc=0;
        dfs(1);
        printf("%d\n",k);
        for(int i=0;i<ans.size();i++)
        {
            printf("%d ",ans[i]);
        }
   }
    //cout << "time: " << (long long)clock() * 1000 / CLOCKS_PER_SEC << " ms" << endl;
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值