题意:
给你一些边,每个边都属于一个确定的公司,告诉你q 个询问,每个询问让你输出两点之间的最短路,并且打印解,连续属于一个公司的线路,只打印收尾。
思路:
这个题赛场上过样例后,只得到了一分。= =
其实就是个很水的dijkstra。
只不过要求的最通畅路线是 要求节点数最小,节点数相同要求换公司线路最小。
这个题wa了好久,原因是 优先队列优先级写反了。
我们只需要简单的修改一下dijkstra即可。
在保证结点最小的情况下,开个新变量记录这个点的换线次数。 那么结点相同在判断 换线次数最小即可。
把路径记录下后 处理路径打印即可。
结点最小 可以让所有边权值都为1.
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <map>
#include <vector>
#include <queue>
using namespace std;
int cnt= 0 ;
map<int,int>mp;
const int inf = 0x3f3f3f3f;
const int maxn = 10000 + 10;
int fid[maxn];
int ID(int x){
if (mp.count(x)){
return mp[x];
}
fid[cnt] = x;
return mp[x] = cnt++;
}
int com[maxn][maxn];
struct Edge{
int f,t,w;
Edge(int f =0,int t = 0,int w = 0):f(f),t(t),w(w){}
};
struct Node{
int u,d;///d 是距离。
int sum;/// sum 是换线总次数
int ori;///ori 目前所在的公司
bool operator < (const Node& rhs) const {
return d > rhs.d || (d == rhs.d && sum > rhs.sum);
}
Node(int u = 0,int d = 0,int sum = 0,int ori = -1):u(u),d(d),sum(sum),ori(ori){}
};
struct DDDDD{
int n,m;
vector<Edge> edges;
vector<int>g[maxn];
priority_queue<Node>q;
bool vis[maxn];
int d[maxn];
int p[maxn];
int dsum[maxn];
void init(int xx){
this->n = xx;
for (int i = 0; i <= n; ++i) g[i].clear();
edges.clear();
m = 0;
while(!q.empty())q.pop();
}
void add(int f,int t,int w){
edges.push_back(Edge(f,t,w));
g[f].push_back(m++);
}
int dij(int s,int t){
for (int i = 0; i <= n; ++i)d[i] = inf;
memset(vis,0,sizeof vis);
memset(p,-1,sizeof p);
memset(dsum,inf,sizeof dsum);
d[s] = 0;
dsum[s] = 0;
q.push(Node(s,0));
while(!q.empty()){
Node nod = q.top(); q.pop();
int cur = nod.u;
if (vis[cur]) continue;
vis[cur] = 1;
for (int i = 0; i < g[cur].size(); ++i){
int v = g[cur][i];
Edge& e = edges[v ];
if (d[e.t] > d[cur] + e.w){
d[e.t] = d[cur] + e.w;
int nxsum = nod.sum,nxori = nod.ori;
if (com[e.t ][cur] != nod.ori){
nxori = com[e.t][cur];
nxsum++;
}
p[e.t] = cur;
dsum[e.t] = nxsum;
q.push(Node(e.t,d[e.t],nxsum,nxori));
}
else if (d[e.t] == d[cur] + e.w){
int nxsum = nod.sum,nxori = nod.ori;
if (com[e.t ][cur] != nod.ori){
nxori = com[e.t][cur];
nxsum++;
}
if (dsum[e.t] > nxsum){
dsum[e.t] = nxsum;
p[e.t] = cur;
q.push(Node(e.t,d[e.t],nxsum,nxori));
}
}
}
}
return d[t];
}
}dic;
vector<int>ans;
int main(){
int n;
scanf("%d", &n);
dic.init(maxn);
for (int i = 1; i <= n; ++i){
int x,la,num;
scanf("%d",&num); scanf("%d",&la);
for (int j = 1; j < num; ++j){
scanf("%d",&x);
int idla = ID(la);
int idx = ID(x);
dic.add(idla,idx,1);
dic.add(idx,idla,1);
com[idla][idx] = com[idx][idla] = i;
la = x;
}
}
int q;
scanf("%d",&q);
while(q--){
int u,v;
scanf("%d %d",&u, &v);
int idu = ID(u), idv = ID(v);
int vv = dic.dij(idu,idv);
int cur = idv;
ans.clear();
while(cur != -1){
ans.push_back(cur);
cur = dic.p[cur];
}
if ((int)ans.size() <= 1){
puts("Sorry, no line is available.");
continue;
}
reverse(ans.begin(),ans.end());
cur = com[ans[0] ][ans[1] ];
ans.push_back(0);
int len = ans.size();
printf("%d\n",len-2);
int s = 0;
for (int i = 1; i < len; ++i){
if (com[ans[i-1] ][ans[i] ] != cur){
printf("Go by the line of company #%d from %.4d to %.4d.\n",cur,fid[ans[s] ], fid[ans[i-1] ]);
s = i-1;
cur = com[ans[i-1] ][ans[i] ];
}
else continue;
}
}
return 0;
}
L3-014. 周游世界
时间限制
200 ms
内存限制
65536 kB
代码长度限制
8000 B
判题程序
Standard
作者
陈越
周游世界是件浪漫事,但规划旅行路线就不一定了…… 全世界有成千上万条航线、铁路线、大巴线,令人眼花缭乱。所以旅行社会选择部分运输公司组成联盟,每家公司提供一条线路,然后帮助客户规划由联盟内企业支持的旅行路线。本题就要求你帮旅行社实现一个自动规划路线的程序,使得对任何给定的起点和终点,可以找出最顺畅的路线。所谓“最顺畅”,首先是指中途经停站最少;如果经停站一样多,则取需要换乘线路次数最少的路线。
输入格式:
输入在第一行给出一个正整数N(<= 100),即联盟公司的数量。接下来有N行,第i行(i=1, ..., N)描述了第i家公司所提供的线路。格式为:
M S[1] S[2] ... S[M]
其中M(<= 100)是经停站的数量,S[i](i=1, ..., M)是经停站的编号(由4位0-9的数字组成)。这里假设每条线路都是简单的一条可以双向运行的链路,并且输入保证是按照正确的经停顺序给出的 —— 也就是说,任意一对相邻的S[i]和S[i+1](i=1, ..., M-1)之间都不存在其他经停站点。我们称相邻站点之间的线路为一个运营区间,每个运营区间只承包给一家公司。环线是有可能存在的,但不会不经停任何中间站点就从出发地回到出发地。当然,不同公司的线路是可能在某些站点有交叉的,这些站点就是客户的换乘点,我们假设任意换乘点涉及的不同公司的线路都不超过5条。
在描述了联盟线路之后,题目将给出一个正整数K(<= 10),随后K行,每行给出一位客户的需求,即始发地的编号和目的地的编号,中间以一空格分隔。
输出格式:
处理每一位客户的需求。如果没有现成的线路可以使其到达目的地,就在一行中输出“Sorry, no line is available.”;如果目的地可达,则首先在一行中输出最顺畅路线的经停站数量(始发地和目的地不包括在内),然后按下列格式给出旅行路线:
Go by the line of company #X1 from S1 to S2. Go by the line of company #X2 from S2 to S3. ......
其中Xi是线路承包公司的编号,Si是经停站的编号。但必须只输出始发地、换乘点和目的地,不能输出中间的经停站。题目保证满足要求的路线是唯一的。
输入样例:
4
7 1001 3212 1003 1204 1005 1306 7797
9 9988 2333 1204 2006 2005 2004 2003 2302 2001
13 3011 3812 3013 3001 1306 3003 2333 3066 3212 3008 2302 3010 3011
4 6666 8432 4011 1306
4
3011 3013
6666 2001
2004 3001
2222 6666
输出样例:
2
Go by the line of company #3 from 3011 to 3013.
10
Go by the line of company #4 from 6666 to 1306.
Go by the line of company #3 from 1306 to 2302.
Go by the line of company #2 from 2302 to 2001.
6
Go by the line of company #2 from 2004 to 1204.
Go by the line of company #1 from 1204 to 1306.
Go by the line of company #3 from 1306 to 3001.
Sorry, no line is available.