zoukankan      html  css  js  c++  java
  • poj 1511 Invitation Cards

    最短路

    题意:  强调是有向图 , n个点(1到n标号)m条边,求出点1到所有点的最短路之和 + 所有点到点1的最短路之和

    什么?求一次最短路,然后 x 2 就是答案? 这样是错的,如果是无向图的话可以这样,因为可以逆回去走。但是有向图显然不是,点1到点a的最短路,和点a到点1的最短路是完全不同的,值不同走过的路径也不同.要求点1到所有点的最短路,直接运行一次最短路即可。但是要求所有点到点1的最短路,难道要对所有点运行一次最短路吗?一看点数就可以否定这个想法。可以这样想,如果点a到点1存在最短路,那么把这条路径的边全部取反,就是点1到点a的最短路了。所有在求了第1次最短路后,将 整个图的边取反,再求一次点1到所有点的最短路就行了,可以知道边都取反后,第一次走过的路径都不会再走到(都取反了),而从点a可能到点1的可能的边都成了点1到点a的可能的边

    代码用了spfa算法,用queue和stack来辅助对时间的影响不大,但是stack稍快一点(只从上次后我发现其实stack都比queue快,一般情况下,更不用题特殊情况了)

    另外用dij+heap也行,朴素的dij应该是超时的,虽然没写

    #include <cstdio>
    #include <cstring>
    #include <queue>
    #include <stack>
    using namespace std;
    #define N 1000010
    #define INF 0x3f3f3f3f
    
    typedef long long ll;
    ll d[N];
    int n,tot;
    int head[N];
    bool ins[N];
    struct edge
    {
        int u,v,w,next;
    }e[N],tt[N];
    
    void add(int u ,int v ,int w , int k)
    {
        e[k].u = u;
        e[k].v = v;
        e[k].w = w;
        e[k].next = head[u];
        head[u] = k;
    }
    
    ll spfa_stack()
    {
        stack<int>sta;
        memset(d,0x3f,sizeof(d));
        memset(ins,false,sizeof(ins));
        while(!sta.empty()) sta.pop();
        d[1] = 0;
        ins[1] = true;
        sta.push(1);
        while(!sta.empty())
        {
            int u = sta.top();
            sta.pop();
            ins[u] = false;
            for(int k=head[u]; k!=-1; k=e[k].next)
            {
                int v =e[k].v;
                int w = e[k].w;
                if( d[u] + w < d[v] )
                {
                    d[v] = d[u] + w;
                    if(!ins[v])
                    {
                        ins[v] = true;
                        sta.push(v);
                    }
                }
            }
        }
        ll res = 0;
        for(int i=1; i<=n ; i++)
            res += d[i];
        return res;
    }
    
    int main()
    {
        int T;
        scanf("%d",&T);
        while(T--)
        {
            scanf("%d%d",&n,&tot);
    
            memset(head,-1,sizeof(head));
            for(int i=0; i<tot; i++)
            {
                int u,v,w;
                scanf("%d%d%d",&u,&v,&w);
                tt[i].u = u; tt[i].v = v; tt[i].w = w;
                add(u,v,w,i);
            }
            ll suma = spfa_stack();
    
            memset(head,-1,sizeof(head));
            for(int i=0; i<tot; i++)
                add(tt[i].v , tt[i].u , tt[i].w , i);
            ll sumb = spfa_stack();
    
            printf("%lld\n",suma+sumb);
        }
        return 0;
    }
  • 相关阅读:
    SQL的四种连接(内连接,外连接)
    MySQL连表操作之一对多
    [转]Mysql连表之多对多
    Hibernate笔记二
    Hibernate框架报错:org.hibernate.PropertyAccessException: IllegalArgumentException occurred while calling setter of com.mikey.hibernate.domain.Person.pid
    Hibernate框架:org.hibernate.exception.SQLGrammarException: Cannot open connection at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java92)
    [转]网络编程三要素
    Hibernate笔记一
    JavaScript高级特征之面向对象笔记
    Myeclipse创建HTML文件中文显示乱码问题
  • 原文地址:https://www.cnblogs.com/scau20110726/p/3060299.html
Copyright © 2011-2022 走看看