题解 | #最短路#

最短路

https://ac.nowcoder.com/acm/problem/15479

本题主要坑点在于无脑加边会超时,顺便吐槽那个xoj操作wa了几发才看出来是异或操作.

点和点的边权为
即和它们的位有关系,可以从位的关系入手,精简边数
不考虑单向通道的情况下,,之间的最短距离应是 ,即不假借其他点而直接转移过来。对最短路长度的贡献取决于二者不同位的个数和位置。一旦引入中间结点,又导致位数贡献变多,不是最优。
现在可以把贡献拆开,两点的不同位数可能不止一位。所有的点都连向和自己只相差一位的点,这样经过有限次位数的变动,可以使得变成,且每次变动的都是不同的位数,因此答案不会变差。
按照上述精简边数建图跑最短路即可

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10,M=5e6+10;
int h[N],e[M],ne[M],w[M],idx;
int dist[N];
bool st[N];
using pii=pair<int,int>;
void add(int a,int b,int c){
    e[idx]=b;
    w[idx]=c;
    ne[idx]=h[a];
    h[a]=idx++;
}
int main(){
    int n,m,C;
    priority_queue<pii,vector<pii>,greater<pii>>pq;
    scanf("%d %d %d",&n,&m,&C);
    memset(h,-1, sizeof h);
    for(int i=0;i<m;i++){
        int a,b,c;
        scanf("%d %d %d",&a,&b,&c);
        add(a,b,c);
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j<<=1){
            if((i^j)>n)continue;
            add(i,(i^j),j*C);//加边
        }
    }
    int beg,end;
    scanf("%d %d",&beg,&end);
    memset(dist,0x3f, sizeof dist);
    dist[beg]=0;
    pq.push({0,beg});
    while(!pq.empty()){
        pii t=pq.top();
        #define F first
        #define S second
        pq.pop();
        if(st[t.S])continue;
        st[t.S]=true;
        for(int i=h[t.S];~i;i=ne[i]){
            int j=e[i];
            if(dist[j]>dist[t.S]+w[i]){
                dist[j]=dist[t.S]+w[i];
                if(!st[j])
                pq.push({dist[j],j});
            }
        }
    }
    cout<<dist[end];

}

全部评论
这份代码有点问题,他处理不了n为2的幂次的情况(因为n这个结点不会有边连向他); 只需要把第24行的i从0开始遍历即可。
3 回复 分享
发布于 2022-06-23 17:04
我来补充一下上边这位大佬的发言。拿第一个测试点为例,如果i从1开始,那么就不会存在某个点与4差一位,即没有边到达4。而若想与4连边,即与4差一位,只能是0,所以0一定要存在。这个时候大家可能还有一个疑问,如果某个点想到达点2^n,经过0的中转,会不会导致这个点到点2^n的距离变大呢?这个是不会的。设某个点为u,标号为2^n的点标号为v,那么u+v=u⨁0 + 0⨁v。为什么这个结论一定会成立呢?已知若两个数按照二进制排列,若每一位上的数都满足一个是1一个是0或者都为0,那么u⨁v=u+v一定成立,例如(10011)⨁(01000)=(11011)换算成十进制为27,而19+8=27。综上,如果n为2的幂次,那么如果不添加0为中转点,就会导致n点无法到达。如果添加了0作为中转点,那么每一个到达0的点,都可以到达n点,且经过中转的距离与直接到达n的距离相等。
1 回复 分享
发布于 2022-07-25 21:23
tql!Orz
点赞 回复 分享
发布于 2022-07-02 17:41
补充一下,实际上从0开始是为了保证中间点不超过n的情况,就比如楼上说的4,(100)_2,实际上可以先由1转移到5或者6,再由(110)或者(101)转移过来的,而并不一定是0,所以0其实不是必须要存在的,但是由于他的代码中限制了最大节点为n,结合栗子,假如n=4的话我们的5就不存在了,所以为了解决这种情况,我们才加入了0节点,所以只要我们限制长度在2^n而不是n的时候,0节点就不需要了
点赞 回复 分享
发布于 2022-12-25 22:26 浙江

相关推荐

11-24 00:11
已编辑
广东工业大学 算法工程师
避雷深圳&nbsp;&nbsp;yidao,试用期&nbsp;6&nbsp;个月。好嘛,试用期还没结束,就直接告诉你尽快找下一家吧,我谢谢您嘞
牛客75408465号:笑死,直属领导和 hr 口径都没统一,各自说了一些离谱的被裁理由,你们能不能认真一点呀,哈哈哈哈哈😅😅😅
点赞 评论 收藏
分享
牛客717484937号:双飞硕没实习挺要命的
点赞 评论 收藏
分享
勇敢的联想人前程似锦:如果我是你,身体素质好我会去参军,然后走士兵计划考研211只需要200多分。
点赞 评论 收藏
分享
评论
8
收藏
分享
牛客网
牛客企业服务