目录
- 题目及翻译
- 题面
- 输入
- 输出
- 输入样例
- 输出样例
- 题目思路
- 注意事项
- AC代码
- C++
题目及翻译
题面
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.
翻译
在电视时代,并没有多少人关注戏剧表演,Malidinesia的古典喜剧演员们意识到了这个事实。他们想要宣传自己的剧院,主要是宣传古典喜剧。他们印制了邀请卡,上面有必要的信息和活动安排。很多学生被雇来向人们分发这些邀请函。每个学生都被分配到了一个公交站,他/她要在那呆一天并且把邀请函给那些公交车乘客。学生们将在这样一个特殊的课上学习到如何影响他人,以及影响他人与抢夺他人之间的区别
城市的公交系统非常特别,每条线路都是单向且只连接两个站点。公交车用半个小时从起点站载乘客到终点站,再从终点站空车回起点,然后等到下一个整半点,比如刚好几点钟,或者刚好几点半。两个站点之间的费用记在一个价格表上并且必须当场支付。这些线路规划时设定了,每次往往返的行程都必须经过一个中央检查站CCS,对每个乘客进行身体扫描检查。
所有ACM的同学们白天离开CCS,每个人去到对应的站点邀请乘客。有多少人就有多少个站点。到了晚上所有学生回到CCS。你的任务是写一个程序帮助ACMer们计算出他们要为学生们支付的最小费用
输入
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.
翻译
输入的第一行是一个正整数N,表示有N个样例。
每个样例第一行有两个整数P和Q,1 <= P,Q <= 1000000。
P是包括CCS在内的站点数,Q是公交线路数。
之后跟着的Q行,每行是对一条公交路线的描述
每一行有三个数字:起点、终点和价格。
CSS被标记为站点1
所有价格之和小于1e9,价格是正整数。
你可以认为无论如何都能从任意站点到达任意站点
输出
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.
翻译
对每个样例,输出ACMer们要为学生支付的最小费用
输入样例
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
输出样例
46
210
题目思路
题面简直全是废话,一开始还想翻译一些,结果根本看不懂,一键翻译之后发现全是废话。。
题目从古董喜剧扯到车站,到最后付钱的到底是谁我都没搞清楚
但这不重要,题目直接看样例就能得出题目意思
我也可以结合题目意思讲一下:
每天从站点1有一群人到每个站点,再从每个站点回到1
所以其实只要求从1到每个点,和从每个点到1的最短路就行
一开始就写的链式前向星+堆优化dijkstra,但是思路错了,把每个点都dijkstra了一遍,本来还想着那我干嘛不floyd,果不其然超时了。
去看了题解,get到一个巧妙的思路
先找正向邻接表从1到每个点的最短距离,for一遍求和
然后把邻接表的边方向调转,这样再求逆向邻接表从1到每个点的最短距离,for一遍求和
因为是从1到每个点,和从每个点到1的最短距离,只要把边逆向就能得出来了,妙啊!
注意事项
注意不要和我一样把每个点都dijkstra一遍
还有,这是有向图!!
题目给了10秒,但是floyd应该还是会超时,而且1e6的范围也顶不住
AC代码
C++
用时3572MS 内存37932K 长度1482B
#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
const int MAXN = 1e6;//数据范围
const int INF = 0x3f3f3f3f;//最大值
struct edge {int to,cost,next;edge(int to = 0,int cost = 0,int next = 0)//构造函数,方便产生edge,而且自带初始化:to(to),cost(cost),next(next) {}bool operator < (const edge &n)const{//重写最小化,修改逻辑,优先队列中需要用return cost > n.cost;}
};
int t,n,m,sum;
int a[MAXN+10],b[MAXN+10],c[MAXN+10];//记录边
edge f[MAXN+10];//链式前向星
int pre[MAXN+10];//链式前向星
int flen;//边数
int vis[MAXN+10];
int dis[MAXN+10];
void init(){memset(pre,-1,sizeof(pre));//链式前向星初始化为-1flen = 0;
}
void add(int x,int y,int cost){//链式前向星建表f[flen].to = y;f[flen].cost = cost;f[flen].next = pre[x];pre[x] = flen++;
}
void dijkstra(int x){//堆优化dijkstra模板题,这里堆用优先队列memset(vis,0,sizeof(vis));//初始化memset(dis,0x3f,sizeof(dis));//初始化dis,初始化后dis内每个元素值为INFpriority_queue<edge> que;//顺便用了edge,其实用不上其中的nextedge now,to;dis[x] = 0;que.push(edge(x,dis[x]));//构造一个从点x经过,花费为0的边,进入堆while(!que.empty()){//di就完事了now = que.top();que.pop();if(vis[now.to])continue;vis[now.to] = 1;1for(int i=pre[now.to];~i;i=f[i].next){//遍历前向星if(dis[f[i].to] > dis[now.to] + f[i].cost){dis[f[i].to] = dis[now.to] + f[i].cost;que.push(edge(f[i].to,dis[f[i].to]));}}}
}
int main() {cin>>t;while(t--){cin>>n>>m;for(int i=0;i<m;++i)cin>>a[i]>>b[i]>>c[i];//记录边的信息sum = 0;init();for(int i=0;i<m;++i)add(a[i],b[i],c[i]);//建立正向表dijkstra(1);for(int i=1;i<=n;++i)sum += dis[i];//统计init();for(int i=0;i<m;++i)add(b[i],a[i],c[i]);//建立逆向表dijkstra(1);for(int i=1;i<=n;++i)sum += dis[i];//统计cout<<sum<<endl;//输出1}return 0;
}
本文作者 CSDN@扶她小藜
个人主页链接 https://blog.csdn.net/weixin_44579869