POJ 1511 Invitation Cards——Dijkstra优先队列优化+反向建图

【题目描述】

In the age of television, not many people attend theater performances. Antique Comedians of Malidinesia are aware of this fact. They want to propagate theater and, most of all, Antique Comedies. They have printed invitation cards with all the necessary information and with the programme. A lot of students were hired to distribute these invitations among the people. Each student volunteer has assigned exactly one bus stop and he or she stays there the whole day and gives invitation to people travelling by bus. A special course was taken where students learned how to influence people and what is the difference between influencing and robbery.

The transport system is very special: all lines are unidirectional and connect exactly two stops. Buses leave the originating stop with passangers each half an hour. After reaching the destination stop they return empty to the originating stop, where they wait until the next full half an hour, e.g. X:00 or X:30, where ‘X’ denotes the hour. The fee for transport between two stops is given by special tables and is payable on the spot. The lines are planned in such a way, that each round trip (i.e. a journey starting and finishing at the same stop) passes through a Central Checkpoint Stop (CCS) where each passenger has to pass a thorough check including body scan.

All the ACM student members leave the CCS each morning. Each volunteer is to move to one predetermined stop to invite passengers. There are as many volunteers as stops. At the end of the day, all students travel back to CCS. You are to write a computer program that helps ACM to minimize the amount of money to pay every day for the transport of their employees.
Input
The input consists of N cases. The first line of the input contains only positive integer N. Then follow the cases. Each case begins with a line containing exactly two integers P and Q, 1 <= P,Q <= 1000000. P is the number of stops including CCS and Q the number of bus lines. Then there are Q lines, each describing one bus line. Each of the lines contains exactly three numbers - the originating stop, the destination stop and the price. The CCS is designated by number 1. Prices are positive integers the sum of which is smaller than 1000000000. You can also assume it is always possible to get from any stop to any other stop.
Output
For each case, print one line containing the minimum amount of money to be paid each day by ACM for the travel costs of its volunteers.
Sample Input

2
2 2
1 2 13
2 1 33
4 6
1 2 10
2 1 60
1 3 20
3 4 10
2 4 5
4 1 50

Sample Output

46
210

【题目分析】
求的是从源点到所有点以及所有点到源点的路程和最小,对于源点到所有点的路程和最小我们很自然的想到Dijkstra,因为数据规模比较大需要用邻接表,我用的是前向星的方式进行储存,虽然用vector也可以,但是听说vector更有可能MLE(因为STL中vector实际要多用一倍的空间)和TLE(因为vector的一些挺简单的操作耗时比一般数组要长)。
但是对于其他所有的点到源点的路程和最小我们直接用Dijkstra显然是不行的,而用Floyed复杂度太高。
这个时候就需要一点点脑洞想到反向建图(图论中反向建图经常会碰到,很多正面看起来难以解决的问题反过来看就会变的简单起来),反向建图后我们再跑一遍Dijkstra,这时候的路径方向全部反过来就是实际上其他所有点到源点的路径。然后再求和就可以啦。
前向星进行储存的时候要注意head数组(保存每个点第一条边的数组)如果初始化为0,边一定要从1开始,否则无法判断到底是没有边了还是指向第一个边,如果习惯从0开始数边应该将head数组初始化为-1.
将结构体作为优先队列的元素的时候需要进行运算符重载,优先队列默认是使用小于号进行比较的,我们应该对小于号进行重载。如果想要按照某个值从大到小重载后还是小于号,如果想要某个值从小到大应该重载为大于号,这是因为优先队列默认是从大到小的,也就是“重载后值越小”的越在后面。
在对Dijkstra用优先队列优化的时候不要进行初始化,也不要将源点设置为已经访问过,如果设为已经访问过就直接退出了。而将dis数组进行初始化以后我们后面就很有可能没有办法将其他节点放入队列。
【AC代码】

/*
*因为将两个过程分别写出来了显得有点丑,空间也有点大
*我们也可以两次建图,用一套数组就好了
*/
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<climits>
#include<queue>
#include<vector>
#include<set>
#include<map>
using namespace std;typedef long long ll;
const int MAXN=1e6+5;
struct node
{int v,next;ll w;node(int _v=0,int _next=0,ll _w=0):v(_v),w(_w),next(_next){}
}Edge1[MAXN],Edge2[MAXN];
struct qnode
{int x; ll d;qnode(int _x=0,ll _d=0):x(_x),d(_d){}bool operator <(const qnode &r)const {return d>r.d;}
}p;
int head1[MAXN],head2[MAXN],tot1,tot2;
bool vis[MAXN];
ll dis1[MAXN],dis2[MAXN],ans;
int n,m;void AddEdge1(int u,int v,ll w)
{tot1++;Edge1[tot1].v=v; Edge1[tot1].w=w; Edge1[tot1].next=head1[u];head1[u]=tot1;
}void AddEdge2(int u,int v,int w)
{tot2++;Edge2[tot2].v=v; Edge2[tot2].w=w; Edge2[tot2].next=head2[u];head2[u]=tot2;
}void Dijkstra1()
{memset(vis,0,sizeof(vis));memset(dis1,0x3f,sizeof(dis1));const int INF=dis1[1];int u,v;// for(int i=head1[1];i;i=Edge1[i].next)// {//     dis1[Edge1[i].v]=Edge1[i].w;// }dis1[1]=0;//vis[1]=true;priority_queue<qnode> q;q.push(qnode(1,0));while(!q.empty()){p=q.top(); q.pop();if(vis[p.x]) continue;vis[p.x]=true;u=p.x;for(int i=head1[u];i;i=Edge1[i].next){v=Edge1[i].v;if(!vis[v]  && dis1[v]>dis1[u]+Edge1[i].w){dis1[v]=dis1[u]+Edge1[i].w;q.push(qnode(v,dis1[v]));}}}
}void Dijkstra2()
{memset(vis,0,sizeof(vis));memset(dis2,0x3f,sizeof(dis2));const int INF=dis2[1];int u,v;// for(int i=head2[1];i;i=Edge2[i].next)// {//     dis2[Edge2[i].v]=Edge2[i].w;// }dis2[1]=0; //vis[1]=true;priority_queue<qnode> q;q.push(qnode(1,0));while(!q.empty()){p=q.top(); q.pop();if(vis[p.x]) continue;vis[p.x]=true;u=p.x;for(int i=head2[u];i;i=Edge2[i].next){v=Edge2[i].v;if(!vis[v] && dis2[v]>dis2[u]+Edge2[i].w){dis2[v]=dis2[u]+Edge2[i].w;q.push(qnode(v,dis2[v]));}}}
}void test()
{for(int i=1;i<=n;i++){printf("%lld ",dis1[i]);}printf("\n");for(int i=1;i<=n;i++){printf("%lld ",dis2[i]);}printf("\n");
}int main()
{int T,u,v; ll w;scanf("%d",&T);while(T--){scanf("%d%d",&n,&m);tot1=0; tot2=0;memset(head1,0,sizeof(head1));memset(head2,0,sizeof(head2));for(int i=0;i<m;i++){scanf("%d%d%lld",&u,&v,&w);AddEdge1(u,v,w); AddEdge2(v,u,w);}Dijkstra1(); Dijkstra2();//test();ans=0;for(int i=1;i<=n;i++){ans+=dis1[i]+dis2[i];}printf("%lld\n",ans);}return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/384070.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

链栈 尹成

http://blog.csdn.net/itcastcpp/article/details/39271661 今天&#xff0c;我们一起用C写链栈&#xff0c;具体如下。 LinkStack.h具体内容&#xff1a; [cpp] view plaincopy #include "StackNode.h" template<typename Type> class LinkStack{ publ…

信号的捕捉以及SIGCHLD信号

一. 信号的捕捉定义 用户提供一个处理函数, 要求内核在处理信号时必须切换到用户态,执行这个函数, 这种方式就叫做信号的捕捉 二. 图解信号的捕捉过程 1. 由上图可以看出,当处理信号的执行动作时用户自定义的时候,此时就需返回该函数去调用该函数, 这就叫做信号的捕捉. 以前我…

链队 尹成

http://blog.csdn.net/itcastcpp/article/details/39271691 今天&#xff0c;我们一起用C写一个链对&#xff0c;具体如下所示。 LinkQueue.h具体内容如下&#xff1a; [cpp] view plaincopy #include "QueueNode.h" template<typename Type> class LinkQueu…

强连通分量入门——Trajan算法

今天学习了强连通分量。 【参考博客】 如果觉得我讲的有些地方难以理解或者存在问题&#xff08;欢迎留言&#xff09;&#xff0c;可以看一下我借鉴的一些大佬的博客&#xff1a; 传送门1 传送门2 【知识储备】 首先我们需要对几个定义有一些概念&#xff1a; 强连通&#xff…

最小栈的实现

所谓最小栈, 就是当前栈顶元素最小, 我们可以这样做, 每次在入栈之前, 将待入栈元素与栈顶元素相比, 每次现将待入栈的元素先入栈, 再将带入栈的元素和较小的元素入栈, 这样就可以保证每次栈顶元素是最小元素. 在出栈的时候规定每次出栈两个元素,这样就可以保证在出栈之后栈顶元…

用C++实现单链表的创建、逆置和输出 的两种方法

http://blog.csdn.net/lfeng_coding/article/details/47300563 题目描述&#xff1a;在已知单链表头节点的情况下&#xff0c;设计算法逆置单链表并输出 方法一&#xff1a;采用首先将头节点指向空&#xff0c;让其变为尾节点&#xff0c;然后利用中间节点 p、q 将其后的节点一…

两个栈实现一个队列

利用两个栈实现一个队列思路是这样的. 首先这个队列包含两个栈, 然后一个栈用来入队列, 一个栈用来出队列 typedef struct QueBy2Stack {SeqStack input;SeqStack output; }QueBy2Stack; 1. 初始化 void QueBy2StackInit(QueBy2Stack* stack) {if(stack NULL){return;//非法…

HDU 5934:Boom——强连通分量+缩点

【题目描述】 There are N bombs needing exploding.Each bomb has three attributes: exploding radius ri, position (xi,yi) and lighting-cost ci which means you need to pay ci cost making it explode.If a un-lighting bomb is in or on the border the exploding ar…

Linux--线程死锁

http://blog.csdn.net/gebushuaidanhenhuai/article/details/73799824 线程为什会死锁&#xff1f;&#xff1f;“锁”又是什么东西&#xff1f;我们这篇博客主要讲一下为什么要给线程加锁&#xff0c;为什么会出现线程死锁&#xff0c;线程死锁怎么解决。 互斥锁 在我的上篇博…

两个队列实现一个栈

用两个队列实现一个栈的原理是这样的. 规定两个队列, 必须有一个队列是非空, 一个队列是空.每次入栈时必须往非空队列中入, 而每次出栈时, 必须将非空队列里的元素装到空队列中, 直到非空队列中只有一个元素时, 此时就将剩下的这个元素出栈即可. 而取栈顶元素时, 和出栈一样, 先…

POJ-1144 Network——Trajan+割点

【题目描述】 A Telephone Line Company (TLC) is establishing a new telephone cable network. They are connecting several places numbered by integers from 1 to N . No two places have the same number. The lines are bidirectional and always connect together tw…

Linux--生产者与消费者

http://blog.csdn.net/gebushuaidanhenhuai/article/details/74011636 基本概念 提到生产者和消费者&#xff0c;我们最有可能想到的是商店卖东西&#xff0c;顾客在货架上(缓冲区&#xff09;买东西。 生产者消费者问题&#xff0c;其实是一个多线程同步问题的经典案例。该问…

进程的挂起以及可重入函数

相关接口     pause 函数用于将进程挂起. 如果信号的处理动作是终止进程, 则进程终止, pause 函数没有返回值; 如果信号的处理动作是忽略, 则进程被挂起, pause函数不返回, 如果信号的处理动作是捕捉, 则调用信号处理动作之后pause 返回 -1.来看一段代码 #include<s…

POJ1236Network of Schools——强连通分量缩点建图

【题目描述】 A number of schools are connected to a computer network. Agreements have been developed among those schools: each school maintains a list of schools to which it distributes software (the “receiving schools”). Note that if B is in the distri…

C——通过调用函数分配内存

http://blog.csdn.net/u012627502/article/details/3579724 1&#xff09;以返回值方式返回&#xff1a;把动态分配的存储位置地址&#xff0c;赋值给指针类型返回值&#xff08;不同于被调用函数的自动变量地址&#xff09; 2&#xff09;以形参形式返回&#xff1a;二级指针类…

gdb调试多进程程序

1.gdb下调试多进程程序只需要以下几条命令即可              除此之外还可以查看正在调试的进程 info inferiors, 同时也可以将当前正在调试的进程切换到另外一个进程中让其取运行     2.代码调试演示 #include<stdio.h> #include<stdlib.h> #…

BZOJ1123-BLO——强连通分量求割点+计数

【题目描述】 Byteotia城市有n个 towns m条双向roads. 每条 road 连接 两个不同的 towns ,没有重复的road. 所有towns连通。Input 输入n<100000 m<500000及m条边Output 输出n个数&#xff0c;代表如果把第i个点去掉&#xff0c;将有多少对点不能互通。Sample Input 5…

关于memcpy和memmove两函数的区别

http://blog.csdn.net/caowei840701/article/details/8491836 [cpp] view plaincopy <p> 关于memcpy和memmove两个c标准库函数&#xff0c;其功能都是将一块内存区域中的指定大小内容复制到目标内存中&#xff0c;在翻阅c标准库实现的源代码我们发现他们是有区别的。&…

判断字符串出栈合法性

先来看说一下思路 接下来就是写代码了 int StackOrder(SeqStack* stack, char* input, char* output, int size_input, int size_output) {if(stack NULL || input NULL || output NULL){return 0;}int i_input 0;int j_output 0;SeqStackType value;for(; j_output <…

CodeForces - 1200C——小模拟

【题目描述】 Amugae is in a very large round corridor. The corridor consists of two areas. The inner area is equally divided by n sectors, and the outer area is equally divided by m sectors. A wall exists between each pair of sectors of same area (inner o…