zoukankan      html  css  js  c++  java
  • path(CCPC网络赛)

    path

    Time Limit: 2000/1500 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)


    Problem Description
    You have a directed weighted graph with n vertexes and m edges. The value of a path is the sum of the weight of the edges you passed. Note that you can pass any edge any times and every time you pass it you will gain the weight.

    Now there are q queries that you need to answer. Each of the queries is about the k-th minimum value of all the paths.
     
    Input
    The input consists of multiple test cases, starting with an integer t (1t100), denoting the number of the test cases.
    The first line of each test case contains three positive integers n,m,q. (1n,m,q5104)

    Each of the next m lines contains three integers ui,vi,wi, indicating that the ith edge is from ui to vi and weighted wi.(1ui,vin,1wi109)

    Each of the next q lines contains one integer k as mentioned above.(1k5104)

    It's guaranteed that Σn ,ΣmΣq,Σmax(k)2.5105 and max(k) won't exceed the number of paths in the graph.
     
    Output
    For each query, print one integer indicates the answer in line.
     
    Sample Input
    1
    2 2 2
    1 2 1
    2 1 2
    3
    4
    Sample Output
    3
    3
    Hint
    1->2 value :1
    2->1 value: 2
    1-> 2-> 1 value: 3
    2-> 1-> 2 value: 3

    题意:n个点m条 边;q次询问;问在图中所有路径权值中第k小的值;
     
    解法,把当前点和走到它时的边压入multiset中;
    #include<bits/stdc++.h>
    using namespace std;
    const long long N=2e5+50;
    struct nn  //用于临时存边,并对边的权值由小到大排序; 
    {
        long long u,v,w;
     
        bool operator < (const nn & other_nn) const
        {
            return w<other_nn.w;
        }
    };
     
    vector<nn>a[N];
     
    struct ss //前向星加边操作
    {
        long long u,v,w,next;
    }edg[N];
    
    long long head[N],sumedg=0;
    void addedg(long long u,long long v,long long w)
    {
        //printf("%lld %lld %lld
    ",u,v,w);    
        edg[sumedg]=(ss){u,v,w,head[u]};
        head[u]=sumedg++;
    }
    
    long long kmax=0,kk[N];
    long long res[N]={0},sum=0;
    long long n,m;
    struct oo //定义一个结构体;item 表示最后到达的点;valu表示走过的边权和
    {
        long long item,valu;
        
        bool operator < (const oo &other)const
        {
            return valu<other.valu;
        }
    };
    multiset<oo>q; //类似于优先队列;可以满足排序,从前后都可以删去;
    void spfa(long long kmax)
    {
    //    printf("%lld(nn)
    ",n); 
        q.clear();
        for(long long i=1;i<=n;i++) q.insert((oo){i,0}); //初始,把{i,0}加入,每个点,和0
    
        while(!q.empty())
        {
        /*    multiset<oo>::iterator it;
            for(it=q.begin();it!=q.end();it++)printf("%lld %lld | ",it->item,it->valu); //便利multiset
            printf("
    ");
            */
            oo now=*q.begin();  //加* 表引用,赋值;
            q.erase(q.begin());//删除第一个
            
            //printf("%lld %lld %lld
    ",now.item,now.valu,q.begin()->item);
            
            
            if(now.valu) //保证从小到大排序;使得每次拿出来的一定是第sum大的
            {
                res[sum++]=now.valu;
            }
            if(sum>=kmax) return;//如果应该找的kmax
            
            for(long long i=head[now.item];i!=-1;i=edg[i].next) //对当前点增广
            {
                q.insert((oo){edg[i].v,edg[i].w+now.valu});
                if(q.size()>kmax+n-sum+5) //一共有kmax+n个数;找到sum个;还需要kmax+n-sum;为了防止multiset爆;
                {
                    q.erase(--q.end());//如果多了,就删除最后的大的
                    if(now.valu+edg[i].w>(*(--q.end())).valu) break;//如果当前比最后的值都大;就没有必要向下找了; 
                }
            }
        }
    }
    int main()
    {
        long long  t;
        scanf("%lld",&t);
        while(t--)
        {
            long long q; 
            sumedg=0;//初始化!!!
            sum=0;
            kmax=0;
            scanf("%lld%lld%lld",&n,&m,&q);
            for(int i=0;i<=n;i++)head[i]=-1,a[i].clear(); //初始化!!! 
            
            for(long long i=0;i<m;i++)
            {
                long long u,v,w;
                scanf("%lld %lld %lld",&u,&v,&w);
                a[u].push_back((nn){u,v,w}); //存起来
            }
     
            for(long long i=1;i<=n;i++)
            {
            //    printf("%lld:%lld
    ",i,a[i].size());
                sort(a[i].begin(),a[i].end());//对vector按边权排序;
                for(long long j=a[i].size()-1;j>=0;j--) //反向加边;因为要找前K小的;而前向星又是越是后建的边,越先访问;
                addedg(a[i][j].u,a[i][j].v,a[i][j].w);
            }
            for(long long i=0;i<q;i++) //取K的max;使得有一个范围大小在;
            {
                scanf("%lld",&kk[i]);
                kmax=max(kmax,kk[i]);
            }
            
            spfa(kmax);
            
          //  for(long long i=0;i<10;i++)printf("%lld ",res[i]); 
            for(long long i=0;i<q;i++) printf("%lld
    ",res[kk[i]-1]);//从0开始
        }
        return 0;
    }
  • 相关阅读:
    基于Yarp的http内网穿透库HttpMouse
    Redis+Lua解决高并发场景抢购秒杀问题
    SQL慢查询排查思路
    webrtc之TURE、STUN、摄像头打开实战
    WebService就该这么学
    超详细 Java 15 新功能介绍
    Java 14 新功能介绍
    Java 17 将要发布,补一下 Java 13 中的新功能
    Java 8 Function 函数接口
    PO/DO/VO/DTO/BO/POJO概念与区别
  • 原文地址:https://www.cnblogs.com/sylvia1111/p/11403763.html
Copyright © 2011-2022 走看看