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;
    }
  • 相关阅读:
    文献阅读报告
    Social LSTM 实现代码分析
    文献阅读报告
    对象不止是一个对象——面向对象设计与构造第四章总结暨课程总结
    当代码遇到数理逻辑——面向对象设计与构造第三章总结
    学会拒绝,是一种智慧——OO电梯章节优化框架的思考
    学会与“有生命力”的对象打交道——面向对象设计与构造第二章总结
    从结构和数字看OO——面向对象设计与构造第一章总结
    爬取漫画DB上的JoJo的奇妙冒险 第七部 飙马野郎
    爬取5家公司(如:阿里巴巴、京东、亚马逊、华为、贵州茅台)百度“资讯”新闻的10页内容
  • 原文地址:https://www.cnblogs.com/sylvia1111/p/11403763.html
Copyright © 2011-2022 走看看