Codeforces Round 800 (Div. 1)C. Keshi in Search of AmShZ 反向dijkstra,并附带权值

Problem - C - Codeforces

目录

题意:

思路:

答疑:

1.为什么反向做呢?

2.为什么是到达点的剩余度数呢?

3.相同路是否可以去重,用个set?

4.如果有多条路相同呢?

参考代码:


题意:

有向图。

从1走到n,可以停一天去封某条路。返回 最优地封完后的 最坏情况

样例3:

思路:

https://www.cnblogs.com/AWhiteWall/p/13158089.html(参考佬的思路)

方法:

比如到 n点 有 3条路,但是剩下两条比最优的一条要远十几天。那么不如用两天时间把这两条路给封掉。(这是正向想的)

所以干脆算最优时直接加上两天 , 取这几种的最小值即可。(加的这两天就是 n 点的“剩余入度”)

——————

所以我们反向建有向图,反向dijktra,每条路的距离(天数)为 1 加上 到此点的剩余度数。

答疑:

1.为什么反向做呢?

因为我们不要离谱长的边,要直接封掉,那么这些路后面的路都不考虑了。这是“趋近于结果的”贪心。

2.为什么是到达点的剩余度数呢?

我们dijkstra是收集的每个点到起始点( n点 )最短路。 每次操作也是用的当前有的最短路。

本次操作是 n 到达这个点 v 的最短路,也是 v 的最优,结合我们的思路,取最坏(封掉其他路),要加上剩余度数。

3.相同路是否可以去重,用个set?

不可以。因为对于最优解,可能要让这些路都封掉。

4.如果有多条路相同呢?

没关系。等到多条中的最后一条时,这条减的度数最小,也是这种路的最优解。(这几条路不是同一“时空”)

参考代码:

发现我的dijkstra板子感觉可以简写~~(可以看看官方题解的简洁代码)

#define endl "\n"
//#define int long long
 
//不能用set,因为那些长的重复的都要删!!
 
const int maxn = 2e5 + 5;
int arr[maxn];
int d[maxn];
int tmpdis = 1;
struct dis_node//放堆里面比长度,但是想知道端点
{
    int dis;
    int next;
    bool operator < (const dis_node& a)
    {
        return dis < a.dis;
    }
    dis_node(int d, int n)
    {
        dis = d; next = n;
    }
};
class cmp
{
public:
    bool operator()(dis_node a, dis_node b)
    {
        return a.dis > b.dis;//
    }
};
void dijkstr(vector<int>& dij, vector<vector<int>>& arr, int ori, int n)
{
    priority_queue<dis_node, vector<dis_node>, cmp>heap;
 
    vector<int>barr(arr.size());
    int cur = ori;
    while (1)
    {
        barr[cur] = 1;
        for (auto next : arr[cur])
        {
            if (dij[next] > dij[cur] + d[next])
            {
                dij[next] = dij[cur] + d[next];
                heap.push(dis_node(dij[next], next));
            }
            d[next]--;
        }
 
        while (heap.size())
        {
            if (barr[heap.top().next] == 0)
                break;
            heap.pop();
        }
        if (heap.size() == 0)break;
        cur = heap.top().next;
        heap.pop();
    }
}
 
void solve()
{
    int n, m;
    cin >> n >> m;
    vector<vector<int>>arr(n+1);
    vector<int>dij(n+1,INT_MAX);
    dij[n] = 0;
    for (int i = 0; i < m; i++)
    {
        int a, b;
        cin >> a >> b;
 
        arr[b].push_back(a);
        d[a]++;
        //a的走法,我们是倒着算的,其实正着是a -> b,
        //我们是用b算的某个a,而且可以认为是当前最小a可走!!!
 
    }
    dijkstr(dij, arr, n, 1);
    cout << dij[1] << endl;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值