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;
    }
  • 相关阅读:
    hdu 5087(次长上升子序列)
    hdu 5086(递推)
    hdu 5084(矩阵操作)
    hdu 5083(模拟)
    hdu 5082(水题)
    高数准备:
    ★ phpStudy安装SSL证书实现https链接
    phpStudy环境安装SSL证书教程
    Qt中切换窗口功能的实现
    LeetCode OJ:Reverse Linked List II(反转链表II)
  • 原文地址:https://www.cnblogs.com/sylvia1111/p/11403763.html
Copyright © 2011-2022 走看看