Codeforces Gym101502 I.Move Between Numbers-最短路(Dijkstra优先队列版和数组版)
2.0 s
256 MB
standard input
standard output
You are given n magical numbers a1, a2, ..., an, such that the length of each of these numbers is 20 digits.
You can move from the ith number to the jth number, if the number of common digits between ai and aj is exactly 17 digits.
The number of common digits between two numbers x and y is computed is follow:
.
Where countXi is the frequency of the ith digit in the number x, and countYi is the frequency of the ith digit in the number y.
You are given two integers s and e, your task is to find the minimum numbers of moves you need to do, in order to finish at number aestarting from number as.
The first line contains an integer T (1 ≤ T ≤ 250), where T is the number of test cases.
The first line of each test case contains three integers n, s, and e (1 ≤ n ≤ 250) (1 ≤ s, e ≤ n), where n is the number of magical numbers, s is the index of the number to start from it, and e is the index of the number to finish at it.
Then n lines follow, giving the magical numbers. All numbers consisting of digits, and with length of 20 digits. Leading zeros are allowed.
For each test case, print a single line containing the minimum numbers of moves you need to do, in order to finish at number ae starting from number as. If there is no answer, print -1.
1
5 1 5
11111191111191111911
11181111111111818111
11811171817171181111
11111116161111611181
11751717818314111118
3
In the first test case, you can move from a1 to a2, from a2 to a3, and from a3 to a5. So, the minimum number of moves is 3 moves.
这个题的题意没怎么看懂,大体的就是数换位置,如果两个串之间相同的数比较个数(数不一定是连续相同的),把个数小的加起来,正好个数等于17的话,这两个串就建立关系。
然后给你起点和终点,求最少次数(好像),就是迪杰斯特拉跑最短路,然而我写的时候,怎么写都是RE,还是猪队友用他优先队列的板子跑过的.
赛后补题,昨天晚上,一晚上都在杠二维数组存的迪杰斯特拉,还找学长要了学长的板子,都跑不过,一晚上放弃。。今天上午,发现,是初始化没写好,把两份代码的初始化都改好之后都跑过了。。。(MDZZ)
代码1:(队友优先队列版的)
1 //I. Move Between Numbers-和猪一样的过了
2 #include<iostream>
3 #include<cstring>
4 #include<cstdio>
5 #include<algorithm>
6 #include<cmath>
7 #include<queue>
8 #include<vector>
9 using namespace std;
10 const int N=1e3+10;
11 const int inf=0x3f3f3f3f;
12 int a[N][N];
13 char ss[N][N];
14 int n; //n个点1~n m 条边 起点 s
15 int d[N],done[N],p[N]; //d[i]表示i点到起点s的最短路距离
16 //done[u]==1表示u点到起点点s的最短路已经找到
17 //p[i]表示起点s到i的最短路径与i点相连的上一条边
18 struct edge //边结构体
19 {
20 int from,to,dis;
21 };
22 vector<edge> edges; //边集 无向图 边数*2
23 vector<int> g[N]; //g数组存的是边的序号
24 struct mindis //压入优先队列的结构体 因为d[u]和u要绑定起来 才可标记 u是否已确定最短路
25 {
26 int d,u;
27 bool operator <(const mindis& rhs)const{
28 return d>rhs.d; //距离最小值优先 距离相等无所谓 随便一个先出 边权是正的 两个会依次访问 不会影想结果
29 }
30 };
31 void init(int n) //每次输入数据清空容器
32 {
33 for(int i=0;i<=n;i++)
34 g[i].clear();
35 edges.clear();
36 }
37 void addedge(int from,int to,int dis) //加边操作
38 {
39 edges.push_back((edge){from,to,dis}); //将边压入边集
40 int k=edges.size();
41 g[from].push_back(k-1); //k-1为边序号 以后调用边集数组要从下标0开始 所以边的编号从0开始 将边序号压入已from为起点的数组
42 }
43 void dijkstra(int s) //主算法
44 {
45 for(int i=0;i<=n;i++) //把距离初始化为 inf 不能用memset 自己估算一下路径最长有多长 inf定义大一点就好
46 d[i]=inf;
47 d[s]=0; //到自己的最短距离直接设为0
48 priority_queue<mindis> q; //优先队列 小顶堆 最小值优先
49 q.push((mindis){0,s});
50 memset(done,0,sizeof(done)); //初始化数组
51 memset(p,-1,sizeof(p));
52 while(!q.empty()) //队列非空
53 {
54 mindis x=q.top(); //取当前最小值
55 q.pop();
56 int u=x.u;
57 if(done[u]==1) //已确定路径直接跳过
58 continue;
59 done[u]=1; //标记 已确定
60 for(int i=0;i<g[u].size();i++)
61 {
62 edge e =edges[g[u][i]]; //g[u][i]表示以u为起点的第i条边在边集edges中的下标
63 if(d[e.to]>d[u]+e.dis) //满足条件更新距离
64 {
65 d[e.to]=d[u]+e.dis;
66 p[e.to]=g[u][i]; //保存路径
67 q.push((mindis){d[e.to],e.to}); //把更新完的值压入队列
68 }
69 }
70 }
71 }
72 int main(){
73 int t,s,e;
74 scanf("%d",&t);
75 while(t--){
76 scanf("%d%d%d",&n,&s,&e);
77 memset(a,0,sizeof(a));
78 for(int i=1;i<=n;i++){
79 cin>>ss[i];
80 for(int j=0;j<20;j++){
81 int temp=ss[i][j]-'0';
82 a[i][temp]++;
83 }
84 }
85 init(n);
86 for(int i=1;i<=n;i++){
87 for(int j=i+1;j<=n;j++){
88 int ret=0;
89 for(int h=0;h<10;h++)
90 ret+=min(a[i][h],a[j][h]);
91 if(ret==17) {
92 int w=1;
93 addedge(i,j,w);
94 addedge(j,i,w);
95 }
96 }
97 }
98 dijkstra(s);
99 if(d[e]==inf)printf("-1\n");
100 else printf("%d\n",d[e]);
101 }
102 return 0;
103 }
代码2:(自己的板子(垃圾板子。。。),二维数组版的)
1 #include<iostream>
2 #include<cstring>
3 #include<cstdio>
4 #include<algorithm>
5 #include<cmath>
6 using namespace std;
7 #include<bits/stdc++.h>
8 using namespace std;
9 const int N=1e3+10;
10 const int INF=0x3f3f3f3f;
11 char ss[N][N];
12 int q[N][N];
13 int a[N][N]; //存数据的边
14 int dist[N]; //记录最短路的距离
15 int vis[N]; //标记是否访问过
16 int n,s,e;
17 void Dijkstra(){ //迪杰斯特拉算法
18 int tmp,v;
19 memset(vis,0,sizeof(vis));
20 for(int i=1;i<=n;i++)
21 dist[i]=a[s][i]; //首先将dist初始化,将起点与其他点的距离先存进去
22 dist[s]=0; //起点到起点距离为0
23 vis[s]=1; //标记起点被访问过
24 for(int i=1;i<=n-1;i++){ //这里修改了
25 tmp=INF;
26 for(int j=1;j<=n;j++){ //下面的也修改了
27 if(vis[j]==0&&tmp>dist[j]){ //未访问过并且找出与当前要查找的点的最短路径(因为与某个点相连的其他点有多个,找出距离最短的,所以for循环一遍)
28 tmp=dist[j];
29 v=j; //用v存一下当前的最短路径的点
30 }
31 }
32 vis[v]=1;//将当前找到的点标记访问过
33 for(int l=1;l<=n;l++){
34 if(!vis[l]) //找出与之相连的点的最短路径
35 dist[l]=min(dist[l],dist[v]+a[v][l]);//更新d
36 }
37 }
38 }
39 int main(){
40 int t;
41 scanf("%d",&t);
42 while(t--){
43 scanf("%d%d%d",&n,&s,&e);
44 for(int i=1;i<=n;i++){
45 for(int j=1;j<=n;j++){
46 if(i==j)a[i][j]=0; //这里修改了
47 else a[i][j]=INF;
48 }
49 }
50 memset(q,0,sizeof(q));
51 for(int i=1;i<=n;i++){
52 cin>>ss[i];
53 for(int j=0;j<20;j++){
54 int temp=ss[i][j]-'0';
55 q[i][temp]++;
56 }
57 }
58 for(int i=1;i<=n;i++){
59 for(int j=i+1;j<=n;j++){
60 int ret=0;
61 for(int h=0;h<10;h++)
62 ret+=min(q[i][h],q[j][h]);
63 if(ret==17) a[i][j]=a[j][i]=1;
64 }
65 }
66 Dijkstra();
67 if(dist[e]==INF)printf("-1\n");
68 else printf("%d\n",dist[e]);
69 }
70 return 0;
71 }
代码3:(学长的板子,初始化一开始也有问题。。。)
1 //I-头铁,再来一次-学长的板子,加油啊,大兄弟-死了,头被打爆,还是RE2,过了,初始化的时候错了。。。
2 #include<iostream>
3 #include<cstring>
4 #include<cstdio>
5 #include<cmath>
6 #include<algorithm>
7 #include<queue>
8 using namespace std;
9 #define MAX 1005
10 const int INF=0x3f3f3f3f;
11 int arc[1005][1005];
12 int d[1005],n,s,e;
13 char ss[MAX][MAX];
14 int q[MAX][MAX];
15 void dijkstra(int s) // 求s 到其他各点的最短路径
16 {
17 int v,w,k,m;
18 int fina[MAX];
19 int p[MAX];
20 memset(fina,0,sizeof(fina));
21 for(v=1;v<=n; v++) //v=1;数组从1开始
22 {
23 d[v] = arc[s][v];
24 }
25 d[s] = 0;
26 fina[s] = 1;
27 for(v=1; v<n; v++)
28 {
29 m = INF;
30 for(w=1; w<=n; w++)
31 {
32 if( fina[w]==0 && d[w]<m )
33 {
34 k = w;
35 m = d[w];
36 }
37 }
38 fina[k] = 1;
39 for(w=1; w<=n; w++)
40 {
41 if( !fina[w]&& (m+arc[k][w] < d[w] ) )
42 {
43 d[w] = m + arc[k][w];
44 p[w] = k;
45 }
46 }
47 }
48 }
49 int main(){
50 int t;
51 scanf("%d",&t);
52 while(t--){
53 scanf("%d%d%d",&n,&s,&e);
54 for(int i=1;i<=n;i++){
55 for(int j=1;j<=n;j++){
56 if(i==j)arc[i][j]=0;
57 else arc[i][j]=INF;
58 }
59 }
60 memset(q,0,sizeof(q));
61 for(int i=1;i<=n;i++){
62 cin>>ss[i];
63 for(int j=0;j<20;j++){
64 int temp=ss[i][j]-'0';
65 q[i][temp]++;
66 }
67 }
68 for(int i=1;i<=n;i++){
69 for(int j=i+1;j<=n;j++){
70 int ret=0;
71 for(int h=0;h<10;h++)
72 ret+=min(q[i][h],q[j][h]);
73 if(ret==17) arc[i][j]=arc[j][i]=1;
74 }
75 }
76 memset(d,0,sizeof(d));
77 dijkstra(s);
78 if(d[e]==INF)printf("-1\n");
79 else printf("%d\n",d[e]);
80 }
81 return 0;
82 }
Codeforces Gym101502 I.Move Between Numbers-最短路(Dijkstra优先队列版和数组版)的更多相关文章
- POJ - 2387 Til the Cows Come Home (最短路Dijkstra+优先队列)
Bessie is out in the field and wants to get back to the barn to get as much sleep as possible before ...
- HDU 1874-畅通project续(最短路Dijkstra+优先队列)
畅通project续 Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total ...
- 最短路--dijkstra+优先队列优化模板
不写普通模板了,还是需要优先队列优化的昂 #include<stdio.h> //基本需要的头文件 #include<string.h> #include<queue&g ...
- 最短路 dijkstra 优先队列
1.裸题 hdu2544 http://acm.hdu.edu.cn/showproblem.php?pid=2544 Way1: 好像不对 #include <cstdio> #incl ...
- 最短路 dijkstra+优先队列+邻接表
http://acm.hdu.edu.cn/showproblem.php?pid=2544 #include<iostream> #include<queue> #inclu ...
- Codeforces 385C Bear and Prime Numbers
题目链接:Codeforces 385C Bear and Prime Numbers 这题告诉我仅仅有询问没有更新通常是不用线段树的.或者说还有比线段树更简单的方法. 用一个sum数组记录前n项和, ...
- 2017 JUST Programming Contest 3.0 I. Move Between Numbers
I. Move Between Numbers time limit per test 2.0 s memory limit per test 256 MB input standard input ...
- Codeforces 385C Bear and Prime Numbers(素数预处理)
Codeforces 385C Bear and Prime Numbers 其实不是多值得记录的一道题,通过快速打素数表,再做前缀和的预处理,使查询的复杂度变为O(1). 但是,我在统计数组中元素出 ...
- 【poj 1724】 ROADS 最短路(dijkstra+优先队列)
ROADS Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 12436 Accepted: 4591 Description N ...
随机推荐
- html页面简单访问限制
PS:突然发现博客园有密码保护功能,已经可以满足基本需求了.博客园还能备份自己的所有数据,做到了数据归用户所有,平台只是展示,真是良心网站,大赞. 想要通过一个站点放一些东西给一些人看,但是又不想让所 ...
- Python基础——异常
捕捉所有异常 for i in range(10): try: input_number=input('write a number') if input_number=='q': break res ...
- GoF23种设计模式之行为型模式之迭代器模式
一.概述 给定一种语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子.二.适用性1.当访问一个聚合对象的内容而无需暴露它的内部表示的时候.2.当对聚合对象的多 ...
- 安装openstack同步数据库时出错解决方法
错误提示:(2003, "Can't connect to MySQL server on 'controller' ([Errno -2] Name or service not know ...
- Centos7 安装 OwnCloud 私有云
OwnCloud 一款文件主机服务软件,就是我们平时使用的云存储,不过这是在自己主机的服务器上建立属于自己的私有云,OwnCloud 使用AGPLv3协议发布.本项目是基于PHP和SQLite,MyS ...
- UVa 1354 枚举子集 Mobile Computing
只要枚举左右两个子天平砝码的集合,我们就能算出左右两个悬挂点到根悬挂点的距离. 但是题中要求找尽量宽的天平但是不能超过房间的宽度,想不到要怎样记录结果. 参考别人代码,用了一个结构体的vector,保 ...
- Ubuntu下安装anaconda和pycharm
折腾了一上午,终于装好了,如下:Python环境的安装: 安装anaconda 建议去https://www.anaconda.com/download/#linux直接用Ubuntu界面的搜狐浏览器 ...
- hdu3613 Best Reward
先manacher.然后前缀和价值,枚举切点,O(1)判断切后是否回文 #include <iostream> #include <cstring> #include < ...
- Oracle数据库的日常使用命令
1. 启动和关闭数据库 sqlplus /nolog; SQL >conn / as sysdba;(上面的两条命令相当于sqlplus ‘/as sysdba’) SQL >st ...
- Leetcode37--->Sudoku Solver(填充数独)
题目: 给定一个不完整的数独,要求填充好数独:最初给出的数独是有效的,且假设一定有答案: 举例: A sudoku puzzle... 解题思路: 该题与青蛙走迷宫问题很相似,都是用深度优先: 代码如 ...