POJ1511-Invitation Cards
继续刷邝斌飞最短路专题
POJ(Time Limit:8000MS、Memory Limit:262144K)
洛谷UVA721(3s、0B) —— 买一送一洛谷SP50(时间限制:洛谷P1342 )—— 再送一个(时间限制:1.00s、内存限制:125.00MB)
最爱的可用平台(总时间限制: 3000ms 内存限制: 65536kB)—— 测评速度超级快,最主要是测试数据强大
HDU(Time Limit: 5000 MS、Memory Limit:65536 K)
第一个洛谷翻译的纯纯一坨屎,买一送一后面送的那个洛谷SP50翻译不错
真是没啥题可出了,也正好释怀了,就刷10个题
往返最短路(奶牛去别人家参加party和这个请柬)问题重复出现了
题意:环路经过1号点,因此在保证了给定的所有线路往返的时候都会经过1号点就可以不用考虑检查站这个事了,然后给你n个点,让你求1到n-1每个点往返路程之和的min
好简单,反存图都写腻了
10^6个点堆优化的迪杰斯特拉
这题P没意义吧
输入数据好头疼,连多少个点都不知道
我这么弱还活在世界上真的对不起
堆优化迪杰斯特拉又忘了
回去看了下奶牛party,感觉最后那个堆优化的迪杰斯特拉模板性太强了,发现ans都没必要用二维,更改后依旧AC
1 #include<stdio.h> 2 #include<iostream> 3 #include<string.h> 4 #include<queue> 5 using namespace std; 6 int n,m,x; 7 int dir[1001][1001]; 8 int dir_go[1001][1001]; 9 struct Node{ 10 int num; 11 int weight; 12 bool operator<(const Node &a)const{ 13 if(weight==a.weight) 14 return num > a.num; 15 return weight>a.weight; 16 } 17 }; 18 int ans[1001]; 19 int maxnum=0; 20 int a,b,c;//放里面就WA 21 int ans_go[1010]; 22 priority_queue<Node>q; 23 Node firstnode; 24 Node thisnode; 25 Node nextnode; 26 int main() 27 { 28 while(scanf("%d%d%d",&n,&m,&x)!=EOF){ 29 while(!q.empty()) 30 q.pop(); 31 memset(dir,0x3f,sizeof(dir)); 32 memset(ans,0x3f,sizeof(ans)); 33 memset(ans_go,0x3f,sizeof(ans_go)); 34 memset(dir_go,0x3f,sizeof(dir_go)); 35 for(int i=0;i<m;i++){ 36 scanf("%d%d%d",&a,&b,&c); 37 dir[a][b]=c; 38 dir_go[b][a]=c; 39 } 40 for(int i=1;i<=n;i++){ 41 dir[i][i]=0; 42 // ans[i][i]=0; 43 dir_go[i][i]=0; 44 // ans_go[i][i]=0; 45 } 46 // ans[x]=0; 47 // ans_go[x]=0; 48 49 // int i=x; 50 firstnode.num=x; 51 firstnode.weight=0; 52 q.push(firstnode); 53 while(!q.empty()){ 54 thisnode=q.top(); 55 q.pop(); 56 for(int j=1;j<=n;j++){ 57 if(ans[j]>thisnode.weight+dir[thisnode.num][j]){ 58 ans[j]=thisnode.weight+dir[thisnode.num][j]; 59 nextnode.num=j; 60 nextnode.weight=ans[j]; 61 q.push(nextnode); 62 } 63 } 64 } 65 // while(!q.empty()) 66 // q.pop(); 67 68 firstnode.num=x; 69 firstnode.weight=0; 70 q.push(firstnode); 71 while(!q.empty()){ 72 thisnode=q.top(); 73 for(int j=1;j<=n;j++){ 74 if(ans_go[j]>thisnode.weight+dir_go[thisnode.num][j]){ 75 ans_go[j]=thisnode.weight+dir_go[thisnode.num][j]; 76 nextnode.num=j; 77 nextnode.weight=ans_go[j]; 78 q.push(nextnode); 79 } 80 } 81 q.pop();//这个顺序无影响 82 } 83 maxnum=0; 84 for(int i=1;i<=n;i++){ 85 if(maxnum<ans[i]+ans_go[i]) 86 maxnum=ans[i]+ans_go[i]; 87 } 88 printf("%d\n",maxnum); 89 } 90 } 91 92 //之前qq也加过邝斌,是一个橙色的太阳头像,叫bin
额啊啊啊算法好头疼艹
以为可以很快AC了
没说点数量,但边最多10^6,点最多10^6+1个吧
妈的写完发现10^6的数组直接控制台运行1s多,二维直接提示开的太大了
1 #include<stdio.h> 2 #include<string.h> 3 #include<queue> 4 #include<iostream> 5 using namespace std; 6 int dir[1000001][1000001]; 7 int dir_reversal[10001][10001]; 8 int D[1000001]; 9 int D_reversal[1000001]; 10 int num_of_n[1001]; 11 int num_n;//D用来存答案的,每次的dis用来存某点的最优解的,且这个解是要赋给D的 12 struct Node{ 13 int num; 14 int dis; 15 }; 16 Node firstnode; 17 Node nextnode; 18 Node thisnode; 19 priority_queue<Node>q; 20 bool operator<(Node a ,Node b){ 21 return a.dis>b.dis; 22 } 23 int main() 24 { 25 freopen("zhishu.txt","r",stdin); 26 int N; 27 int P,Q;//这题P没意义吧? 28 while(cin>>N){ 29 while(N--){ 30 num_n=0; 31 memset(num_of_n,0,sizeof(num_of_n)); 32 memset(dir,0x3f,sizeof(dir));//没这句不行,调试好久 33 memset(dir_reversal,0x3f,sizeof(dir_reversal)); 34 cin>>P>>Q; 35 for(int i=1;i<=Q;i++){ 36 int a,b,c; 37 scanf("%d%d%d",&a,&b,&c); 38 dir[a][b]=c; 39 dir_reversal[b][a]=c; 40 // cout<<dir_reversal[1][2]<<endl; 41 //cout<<dir_reversal[1][2]<<endl; 42 if(num_of_n[a]==0){ 43 num_n++; 44 num_of_n[a]=1; 45 } 46 if(num_of_n[b]==0){ 47 num_n++; 48 num_of_n[b]=1; 49 }//这两句单纯看有多少个n,提说的P是经过1号点的路线数,并没说总共多少个n 50 } 51 memset(D,0x3f,sizeof(D)); 52 firstnode.num=1; 53 firstnode.dis=0; 54 D[1]=0; 55 // cout<<"D4 "<<D[4]<<endl; 56 q.push(firstnode); 57 while(!q.empty()){ 58 thisnode=q.top();//最小 59 q.pop(); 60 int u=thisnode.num; 61 int w=thisnode.dis; 62 for(int i=1;i<=num_n;i++){ 63 // cout<<"i:"<<i<<" "<<D[i]<<" u:"<<u<<" "<<D[u]<<" "<<dir[u][i]<<" w:"<<w<<endl; 64 if(D[i]>w+dir[u][i]){//松弛 总写错 65 D[i]=w+dir[u][i]; 66 // if(D[4]==0) 67 // cout<<"+"<<w<<" "<<u<<" "<<i<<" "<<dir[u][i]<<endl; 68 // cout<<"&"<<D[2]<<endl; 69 // cout<<"_"<<D[4]<<endl; 70 nextnode.num=i; 71 nextnode.dis=D[i]; 72 q.push(nextnode); 73 } 74 } 75 } 76 //cout<<"#"<<D[2]<<endl; 77 //cout<<"!"<<D[3]<<endl; 78 //cout<<"*"<<D[4]<<endl; 79 memset(D_reversal,0x3f,sizeof(D_reversal)); 80 firstnode.num=1; 81 firstnode.dis=0; 82 D_reversal[1]=0; 83 q.push(firstnode); 84 while(!q.empty()){ 85 thisnode=q.top();//最小 86 q.pop(); 87 int u=thisnode.num; 88 int w=thisnode.dis; 89 for(int i=1;i<=num_n;i++){ 90 if(D_reversal[i]>w+dir_reversal[u][i]){//松弛 91 D_reversal[i]=w+dir_reversal[u][i]; 92 nextnode.num=i; 93 nextnode.dis=D_reversal[i]; 94 q.push(nextnode); 95 } 96 } 97 } 98 //cout<<"@"<<D_reversal[2]<<endl; 99 int min=0; 100 for(int i=1;i<=num_n;i++){ 101 min=min+D_reversal[i]+D[i]; 102 } 103 cout<<min<<endl; 104 } 105 } 106 }
改用之前学过的洛谷那人的vector写法,继续抄ljcljc和wjy666的语法
最近都是用这个语法(vector)来写贝尔曼和SPFA,现在换到迪杰斯特拉(之前一直是邻接矩阵写的,现在点太多,10^6个,开10^6二维数组编译不过),又写的吭吃瘪肚的,vector和迪杰斯特拉结合的好题
但是贝尔曼和SPFA都是只需要点进来即可,全部更新松弛检验,但迪杰斯特拉好像用不了vector写法啊,需要每次找最小,那不仅顶点还需要权值也一起进队列,但那就需要我把1号顶点链接的顶点都加进来,艹,我知道P有啥用了。
啊不对,依旧没用
麻痹的突然发现最经典的迪杰斯特拉的题目,用SPFA/贝尔曼也可以,AC后老子偏要用SPFA写一写
回顾下更加理解:
贝尔曼/SPFA是每次找某点相邻,说人话这个相邻指的就是某点所有出度。
迪杰斯特拉是每次找距离顶点最近的点
打算重构下代码,发现还是差太多了,没真正理解啊,不仅最短路算法,连vector、结构体这些语法都没理解
回顾贝尔曼算法、虫洞负环ljcljc和wjy666的vector存图写法、第一道迪杰斯特拉题目博客里的图、照着奶牛party博客里堆优化的算法和语法,“抄”
tmd结合vector存图写迪杰斯特拉好难啊,好几次想放弃,这是目前学到最难受的题目
1 #include<stdio.h> 2 #include<string.h> 3 #include<queue> 4 #include<iostream> 5 #include<vector> 6 using namespace std; 7 //int D[1000001]; 8 //int D_reversal[1000001]; 9 int num_of_n[1000001]; 10 int num_n; 11 struct Node{ 12 int num; 13 int dis_from_v1; 14 }node; 15 struct Edge{ 16 int to; 17 int dis_uv; 18 }edge; 19 20 vector<Edge>G[1000001]; 21 vector<Edge>G_reversal[1000001]; 22 23 priority_queue<Edge>q; 24 priority_queue<Edge>q_reversal; 25 bool operator<(Node a,Node b){ 26 return a.dis_from_v1>b.dis_from_v1; 27 } 28 int main() 29 { 30 freopen("zhishu.txt","r",stdin); 31 int N; 32 int P,Q;//这题P没意义吧? 33 while(cin>>N){ 34 while(N--){ 35 num_n=0; 36 memset(num_of_n,0,sizeof(num_of_n)); 37 cin>>P>>Q; 38 for(int i=1;i<=Q;i++){ 39 int a,b,c; 40 scanf("%d%d%d",&a,&b,&c); 41 42 edge.to=b; 43 edge.dis_uv=c; 44 G[a].push_back(edge); 45 // if(a==1){ 46 // node.num=1; 47 // node.dis_from_v1=0; 48 // q.push(node); 49 // } 50 51 edge.to=a; 52 edge.dis_uv=c; 53 G_reversal[b].push_back(edge); 54 if(b==1){ 55 node.num=1; 56 node.dis_from_v1=0; 57 q_reversal.push(node); 58 } 59 60 if(num_of_n[a]==0){ 61 num_n++; 62 num_of_n[a]=1; 63 } 64 if(num_of_n[b]==0){ 65 num_n++; 66 num_of_n[b]=1; 67 } 68 69 } 70 memset(D,0x3f,sizeof(D)); 71 D[1]=0; 72 while(!q.empty()){ 73 thisedge=q.top();//最小 74 q.pop(); 75 // for(int i=1;i<=num_n;i++){ 76 for(int i=1;i<=G[u].size();i++){//本质 77 int v=G[thisedge.num][i].to; 78 int w=G[thisedge.dis][i].dis; 79 if(D[v]>dir[u][i]+w){//松弛 总写错 80 D[i]=dir[u][i]+w; 81 nextnode.num=i; 82 nextnode.dis=D[i]; 83 q.push(nextnode); 84 } 85 } 86 } 87 88 memset(D_reversal,0x3f,sizeof(D_reversal)); 89 D_reversal[1]=0; 90 while(!q.empty()){ 91 thisnode=q.top();//最小 92 q.pop(); 93 int u=thisnode.num; 94 int w=thisnode.dis; 95 for(int i=1;i<=num_n;i++){ 96 if(D_reversal[i]>w+dir_reversal[u][i]){//松弛 97 D_reversal[i]=w+dir_reversal[u][i]; 98 nextnode.num=i; 99 nextnode.dis=D_reversal[i]; 100 q.push(nextnode); 101 } 102 } 103 } 104 int min=0; 105 for(int i=1;i<=num_n;i++){ 106 min=min+D_reversal[i]+D[i]; 107 } 108 cout<<min<<endl; 109 } 110 } 111 }
感觉需要有edge和node两个结构体结合到一起,实在写不下去了,这个数量级的存图我束手无策,大脑CPU给我想烧掉了,之前数量级小的时候我刷的都是假的迪杰斯特拉么??代码71行理应是遍历所有个点,但我把点存到了G容器里,导致每次只能找到以顶点为出度的点,但不这么写到容器里又不知道怎么用vector存图,写精分了(脑子里始终有且仅有虫洞那两个洛谷选手的vector模板,其他不会了)
1 #include<stdio.h> 2 #include<string.h> 3 #include<queue> 4 #include<iostream> 5 #include<vector> 6 using namespace std; 7 //int D[1000001]; 8 //int D_reversal[1000001]; 9 int num_of_n[1000001]; 10 int num_n; 11 struct Message{ 12 int from; 13 int to; 14 int dis_from_v1; 15 int dis_uv; 16 }; 17 Message mes; 18 Message firstmes; 19 Message nestmes; 20 21 vector<Edge>G[1000001]; 22 vector<Edge>G_reversal[1000001]; 23 24 priority_queue<Edge>q; 25 priority_queue<Edge>q_reversal; 26 bool operator<(Node a,Node b){ 27 return a.dis_from_v1>b.dis_from_v1; 28 } 29 int main() 30 { 31 freopen("zhishu.txt","r",stdin); 32 int N; 33 int P,Q;//这题P没意义吧? 34 while(cin>>N){ 35 while(N--){ 36 num_n=0; 37 memset(num_of_n,0,sizeof(num_of_n)); 38 cin>>P>>Q; 39 for(int i=1;i<=Q;i++){ 40 int a,b,c; 41 scanf("%d%d%d",&a,&b,&c); 42 43 mes.from=a; 44 mes.to=b; 45 mes.dis_uv=c; 46 G[a].push_back(edge); 47 48 49 mes.from=b; 50 mes.to=a; 51 mes.dis_uv=c; 52 G_reversal[b].push_back(edge); 53 54 if(num_of_n[a]==0){ 55 num_n++; 56 num_of_n[a]=1; 57 } 58 if(num_of_n[b]==0){ 59 num_n++; 60 num_of_n[b]=1; 61 } 62 63 } 64 memset(D,0x3f,sizeof(D)); 65 firstmes.from=1; 66 firstmes.dis_from_v1=0; 67 while(!q.empty()){ 68 thisedge=q.top();//最小 69 q.pop(); 70 for(int i=1;i<=num_n;i++){ 71 int v=G[thisedge.num][i].to;//实在写不下去了 72 int w=G[thisedge.dis][i].dis; 73 if(D[v]>dir[u][i]+w){//松弛 总写错 74 D[i]=dir[u][i]+w; 75 nextnode.num=i; 76 nextnode.dis=D[i]; 77 q.push(nextnode); 78 } 79 } 80 } 81 82 memset(D_reversal,0x3f,sizeof(D_reversal)); 83 D_reversal[1]=0; 84 while(!q.empty()){ 85 thisnode=q.top();//最小 86 q.pop(); 87 int u=thisnode.num; 88 int w=thisnode.dis; 89 for(int i=1;i<=num_n;i++){ 90 if(D_reversal[i]>w+dir_reversal[u][i]){//松弛 91 D_reversal[i]=w+dir_reversal[u][i]; 92 nextnode.num=i; 93 nextnode.dis=D_reversal[i]; 94 q.push(nextnode); 95 } 96 } 97 } 98 int min=0; 99 for(int i=1;i<=num_n;i++){ 100 min=min+D_reversal[i]+D[i]; 101 } 102 cout<<min<<endl; 103 } 104 } 105 }
改用SPFA写(脑子已经写傻了,懵懵的,莫名其妙就AC了,SPFA确实简单,难怪有人说要降黄,但迪杰斯特拉就难了,待会学下别人的)
AC代码
1 #include<stdio.h> 2 #include<string.h> 3 #include<queue> 4 #include<iostream> 5 #include<vector> 6 using namespace std; 7 int D[1000001]; 8 int D_reversal[1000001]; 9 int num_of_n[1000001]; 10 int num_n; 11 struct Edge{ 12 int to; 13 int w; 14 } edge; 15 16 vector<Edge>G[1000001]; 17 vector<Edge>G_reversal[1000001]; 18 queue<int>q; 19 int main() 20 { 21 // freopen("zhishu.txt","r",stdin); 22 int N; 23 int P,Q;//这题P没意义吧? 24 while(cin>>N){ 25 while(N--){ 26 num_n=0; 27 memset(G,0,sizeof(G));//忘记写了 28 memset(G_reversal,0,sizeof(G_reversal)); 29 memset(num_of_n,0,sizeof(num_of_n)); 30 cin>>P>>Q; 31 for(int i=1;i<=Q;i++){ 32 int a,b,c; 33 scanf("%d%d%d",&a,&b,&c); 34 35 edge.to=b; 36 edge.w=c; 37 G[a].push_back(edge); 38 edge.to=a; 39 edge.w=c; 40 G_reversal[b].push_back(edge); 41 if(num_of_n[a]==0){ 42 num_n++; 43 num_of_n[a]=1; 44 } 45 if(num_of_n[b]==0){ 46 num_n++; 47 num_of_n[b]=1; 48 } 49 50 } 51 52 //cout<<"%"<<G[1].size()<<endl; 53 //cout<<"@"<<G_reversal[1].size()<<endl; 54 55 memset(D,0x3f,sizeof(D)); 56 q.push(1); 57 D[1]=0; 58 while(!q.empty()){ 59 int u=q.front(); 60 q.pop(); 61 for(int i=0;i<G[u].size();i++){ 62 int v=G[u][i].to; 63 int w=G[u][i].w; 64 // cout<<"#"<<u<<" "<<v<<endl; 65 if(D[v]>D[u]+w){ 66 D[v]=D[u]+w; 67 q.push(v); 68 } 69 } 70 } 71 72 memset(D_reversal,0x3f,sizeof(D_reversal)); 73 q.push(1); 74 D_reversal[1]=0; 75 while(!q.empty()){ 76 int u=q.front(); 77 q.pop(); 78 for(int i=0;i<G_reversal[u].size();i++){ 79 int v=G_reversal[u][i].to; 80 int w=G_reversal[u][i].w; 81 if(D_reversal[v]>D_reversal[u]+w){ 82 D_reversal[v]=D_reversal[u]+w; 83 q.push(v); 84 } 85 } 86 } 87 88 89 int min=0; 90 for(int i=1;i<=num_n;i++){ 91 min=min+D_reversal[i]+D[i]; 92 } 93 cout<<min<<endl; 94 } 95 } 96 }
好奇反复缩小发现:
洛谷SP50(来自SPOJ),把上面AC代码的所有数组开到25000也是可以的,20000就RE,证明点数并没有很多,那其实迪杰斯特拉的矩阵存图我也可以AC,但偏偏要学其他方法,此题题解都是SPFA
洛谷UVA721(来自uva),数据大一点,要开到200000,AC代码把上面的弄成200000就行了
洛谷P1342(路人提供),就牛逼了,一个是直接把P改成了点数,一个是把w权值从累和是10^9改成了一个是10^9,还有就是输入变了(不用先输入数据个数),我的代码RE+TLE了,但原因就是输入格式题目变了(再具体点就是这道题那个60,会当作m边数,当输入完60行边信息,下一行再进行输入就是前两个数当作n和m,然后第三个数理应是某点的编号,但会当作一个距离给数组,即最大10^9,可点的编号开的最大就是10^6,哎我这强迫症啊,研究好久为啥会报错RE,旁有女生还总无法专心),没有初始的一行数据个数,数组开到30000即可,但要long long int。AC代码
1 #include<stdio.h> 2 #include<string.h> 3 #include<queue> 4 #include<iostream> 5 #include<vector> 6 using namespace std; 7 long long int D[30000]; 8 long long int D_reversal[30000]; 9 int num_of_n[30000]; 10 int num_n; 11 struct Edge{ 12 int to; 13 int w; 14 } edge; 15 16 vector<Edge>G[30000]; 17 vector<Edge>G_reversal[30000]; 18 queue<int>q; 19 int main() 20 { 21 // freopen("zhishu.txt","r",stdin); 22 // int N; 23 int P,Q;//这题P没意义吧? 24 // while(scanf("%d",&N)!=EOF){ 25 while(scanf("%d%d",&P,&Q)!=EOF){ 26 num_n=0; 27 memset(G,0,sizeof(G));//忘记写了 28 memset(G_reversal,0,sizeof(G_reversal)); 29 memset(num_of_n,0,sizeof(num_of_n)); 30 // cin>>P>>Q; 31 for(int i=1;i<=Q;i++){ 32 int a,b,c; 33 scanf("%d%d%d",&a,&b,&c); 34 edge.to=b; 35 edge.w=c; 36 G[a].push_back(edge); 37 edge.to=a; 38 edge.w=c; 39 G_reversal[b].push_back(edge); 40 if(num_of_n[a]==0){ 41 num_n++; 42 num_of_n[a]=1; 43 } 44 if(num_of_n[b]==0){ 45 num_n++; 46 num_of_n[b]=1; 47 } 48 49 } 50 51 //cout<<"%"<<G[1].size()<<endl; 52 //cout<<"@"<<G_reversal[1].size()<<endl; 53 54 memset(D,0x3f,sizeof(D)); 55 q.push(1); 56 D[1]=0; 57 while(!q.empty()){ 58 int u=q.front(); 59 q.pop(); 60 for(int i=0;i<G[u].size();i++){ 61 int v=G[u][i].to; 62 int w=G[u][i].w; 63 // cout<<"#"<<u<<" "<<v<<endl; 64 if(D[v]>D[u]+w){ 65 D[v]=D[u]+w; 66 q.push(v); 67 } 68 } 69 } 70 memset(D_reversal,0x3f,sizeof(D_reversal)); 71 q.push(1); 72 D_reversal[1]=0; 73 while(!q.empty()){ 74 int u=q.front(); 75 q.pop(); 76 for(int i=0;i<G_reversal[u].size();i++){ 77 int v=G_reversal[u][i].to; 78 int w=G_reversal[u][i].w; 79 if(D_reversal[v]>D_reversal[u]+w){ 80 D_reversal[v]=D_reversal[u]+w; 81 q.push(v); 82 } 83 } 84 } 85 86 87 long long int min=0; 88 for(int i=1;i<=num_n;i++){ 89 min=min+D_reversal[i]+D[i]; 90 } 91 // cout<<min<<endl; 92 printf("%lld\n",min); 93 // } 94 } 95 }
POJ(Central Europe 1998),md说是和小于10^9,tmdWA半天,开long long int才AC,且数组开1000001,1000000都不行,AC代码(看这题提交记录Online Status最少有2s的,Status第一名625ms,我7.7s)
1 #include<stdio.h> 2 #include<string.h> 3 #include<queue> 4 #include<iostream> 5 #include<vector> 6 using namespace std; 7 long long int D[1000001]; 8 long long int D_reversal[1000001]; 9 int num_of_n[1000001]; 10 int num_n; 11 struct Edge{ 12 int to; 13 int w; 14 } edge; 15 16 vector<Edge>G[1000001]; 17 vector<Edge>G_reversal[1000001]; 18 queue<int>q; 19 int main() 20 { 21 // freopen("zhishu.txt","r",stdin); 22 int N; 23 int P,Q;//这题P没意义吧? 24 while(cin>>N){ 25 while(N--){ 26 num_n=0; 27 memset(G,0,sizeof(G));//忘记写了 28 memset(G_reversal,0,sizeof(G_reversal)); 29 memset(num_of_n,0,sizeof(num_of_n)); 30 cin>>P>>Q; 31 for(int i=1;i<=Q;i++){ 32 int a,b,c; 33 scanf("%d%d%d",&a,&b,&c); 34 35 edge.to=b; 36 edge.w=c; 37 G[a].push_back(edge); 38 edge.to=a; 39 edge.w=c; 40 G_reversal[b].push_back(edge); 41 if(num_of_n[a]==0){ 42 num_n++; 43 num_of_n[a]=1; 44 } 45 if(num_of_n[b]==0){ 46 num_n++; 47 num_of_n[b]=1; 48 } 49 50 } 51 52 //cout<<"%"<<G[1].size()<<endl; 53 //cout<<"@"<<G_reversal[1].size()<<endl; 54 55 memset(D,0x3f,sizeof(D)); 56 q.push(1); 57 D[1]=0; 58 while(!q.empty()){ 59 int u=q.front(); 60 q.pop(); 61 for(int i=0;i<G[u].size();i++){ 62 int v=G[u][i].to; 63 int w=G[u][i].w; 64 // cout<<"#"<<u<<" "<<v<<endl; 65 if(D[v]>D[u]+w){ 66 D[v]=D[u]+w; 67 q.push(v); 68 } 69 } 70 } 71 72 memset(D_reversal,0x3f,sizeof(D_reversal)); 73 q.push(1); 74 D_reversal[1]=0; 75 while(!q.empty()){ 76 int u=q.front(); 77 q.pop(); 78 for(int i=0;i<G_reversal[u].size();i++){ 79 int v=G_reversal[u][i].to; 80 int w=G_reversal[u][i].w; 81 if(D_reversal[v]>D_reversal[u]+w){ 82 D_reversal[v]=D_reversal[u]+w; 83 q.push(v); 84 } 85 } 86 } 87 88 89 long long int min=0; 90 for(int i=1;i<=num_n;i++){ 91 min=min+D_reversal[i]+D[i]; 92 } 93 cout<<min<<endl; 94 } 95 } 96 }
可用平台(Central Europe 1998),POJ上AC的代码居然MLE,开少了RE,md,不愧是最强OJ —— 提示里说vector会卡?
HDU(Central Europe 1998),草你血奶奶,开300001AC的,开500001返回MLE,我AC代码4s,看Realtime Status有1.1s过的,Statistic排行榜更牛逼有第一名156ms,我的AC代码
1 #include<stdio.h> 2 #include<string.h> 3 #include<queue> 4 #include<iostream> 5 #include<vector> 6 using namespace std; 7 long long int D[300001]; 8 long long int D_reversal[300001]; 9 int num_of_n[300001]; 10 int num_n; 11 struct Edge{ 12 int to; 13 int w; 14 } edge; 15 16 vector<Edge>G[300001]; 17 vector<Edge>G_reversal[300001]; 18 queue<int>q; 19 int main() 20 { 21 // freopen("zhishu.txt","r",stdin); 22 int N; 23 int P,Q;//这题P没意义吧? 24 while(cin>>N){ 25 while(N--){ 26 num_n=0; 27 memset(G,0,sizeof(G));//忘记写了 28 memset(G_reversal,0,sizeof(G_reversal)); 29 memset(num_of_n,0,sizeof(num_of_n)); 30 cin>>P>>Q; 31 for(int i=1;i<=Q;i++){ 32 int a,b,c; 33 scanf("%d%d%d",&a,&b,&c); 34 35 edge.to=b; 36 edge.w=c; 37 G[a].push_back(edge); 38 edge.to=a; 39 edge.w=c; 40 G_reversal[b].push_back(edge); 41 if(num_of_n[a]==0){ 42 num_n++; 43 num_of_n[a]=1; 44 } 45 if(num_of_n[b]==0){ 46 num_n++; 47 num_of_n[b]=1; 48 } 49 50 } 51 52 //cout<<"%"<<G[1].size()<<endl; 53 //cout<<"@"<<G_reversal[1].size()<<endl; 54 55 memset(D,0x3f,sizeof(D)); 56 q.push(1); 57 D[1]=0; 58 while(!q.empty()){ 59 int u=q.front(); 60 q.pop(); 61 for(int i=0;i<G[u].size();i++){ 62 int v=G[u][i].to; 63 int w=G[u][i].w; 64 // cout<<"#"<<u<<" "<<v<<endl; 65 if(D[v]>D[u]+w){ 66 D[v]=D[u]+w; 67 q.push(v); 68 } 69 } 70 } 71 72 memset(D_reversal,0x3f,sizeof(D_reversal)); 73 q.push(1); 74 D_reversal[1]=0; 75 while(!q.empty()){ 76 int u=q.front(); 77 q.pop(); 78 for(int i=0;i<G_reversal[u].size();i++){ 79 int v=G_reversal[u][i].to; 80 int w=G_reversal[u][i].w; 81 if(D_reversal[v]>D_reversal[u]+w){ 82 D_reversal[v]=D_reversal[u]+w; 83 q.push(v); 84 } 85 } 86 } 87 88 89 long long int min=0; 90 for(int i=1;i<=num_n;i++){ 91 min=min+D_reversal[i]+D[i]; 92 } 93 cout<<min<<endl; 94 } 95 } 96 }
至此六大平台只有可用平台没AC —— 发现SPFA+vector真的好慢啊,但时间复杂度先不研究
先统计下每个平台AC时间(随时更新) —— 我都是按照最大1000001开的:
洛谷SP50:
要求:559ms、1.46GB
我的:170ms、72.00MB、代码长度2.49KB
我的代码(vector存图+SPFA) —— 实际测试数据点只有不到25000个
1 #include<stdio.h> 2 #include<string.h> 3 #include<queue> 4 #include<iostream> 5 #include<vector> 6 using namespace std; 7 int D[1000001]; 8 int D_reversal[1000001]; 9 int num_of_n[1000001]; 10 int num_n; 11 struct Edge{ 12 int to; 13 int w; 14 } edge; 15 16 vector<Edge>G[1000001]; 17 vector<Edge>G_reversal[1000001]; 18 queue<int>q; 19 int main() 20 { 21 // freopen("zhishu.txt","r",stdin); 22 int N; 23 int P,Q;//这题P没意义吧? 24 while(cin>>N){ 25 while(N--){ 26 num_n=0; 27 memset(G,0,sizeof(G));//忘记写了 28 memset(G_reversal,0,sizeof(G_reversal)); 29 memset(num_of_n,0,sizeof(num_of_n)); 30 cin>>P>>Q; 31 for(int i=1;i<=Q;i++){ 32 int a,b,c; 33 scanf("%d%d%d",&a,&b,&c); 34 35 edge.to=b; 36 edge.w=c; 37 G[a].push_back(edge); 38 edge.to=a; 39 edge.w=c; 40 G_reversal[b].push_back(edge); 41 if(num_of_n[a]==0){ 42 num_n++; 43 num_of_n[a]=1; 44 } 45 if(num_of_n[b]==0){ 46 num_n++; 47 num_of_n[b]=1; 48 } 49 50 } 51 52 //cout<<"%"<<G[1].size()<<endl; 53 //cout<<"@"<<G_reversal[1].size()<<endl; 54 55 memset(D,0x3f,sizeof(D)); 56 q.push(1); 57 D[1]=0; 58 while(!q.empty()){ 59 int u=q.front(); 60 q.pop(); 61 for(int i=0;i<G[u].size();i++){ 62 int v=G[u][i].to; 63 int w=G[u][i].w; 64 // cout<<"#"<<u<<" "<<v<<endl; 65 if(D[v]>D[u]+w){ 66 D[v]=D[u]+w; 67 q.push(v); 68 } 69 } 70 } 71 72 memset(D_reversal,0x3f,sizeof(D_reversal)); 73 q.push(1); 74 D_reversal[1]=0; 75 while(!q.empty()){ 76 int u=q.front(); 77 q.pop(); 78 for(int i=0;i<G_reversal[u].size();i++){ 79 int v=G_reversal[u][i].to; 80 int w=G_reversal[u][i].w; 81 if(D_reversal[v]>D_reversal[u]+w){ 82 D_reversal[v]=D_reversal[u]+w; 83 q.push(v); 84 } 85 } 86 } 87 88 89 int min=0; 90 for(int i=1;i<=num_n;i++){ 91 min=min+D_reversal[i]+D[i]; 92 } 93 cout<<min<<endl; 94 } 95 } 96 }
我的:210ms、69.00MB
我的代码(堆优化优先队列迪杰斯特拉+vector存图+手写pair)
1 #include<stdio.h> 2 #include<string.h> 3 #include<queue> 4 #include<iostream> 5 #include<vector> 6 using namespace std; 7 int D[1000001]; 8 int D_reversal[1000001]; 9 struct Node{ 10 int to; 11 int dis_uv; 12 } node; 13 struct forPair{ 14 int num; 15 int dis_from_v1; 16 }forpair; 17 vector<Node>G[1000001]; 18 vector<Node>G_reversal[1000001]; 19 priority_queue<forPair>q; 20 bool operator<(forPair a,forPair b){ 21 return a.dis_from_v1>b.dis_from_v1; 22 } 23 int main() 24 { 25 // freopen("zhishu.txt","r",stdin); 26 int N; 27 int P,Q; 28 while(cin>>N){ 29 while(N--){ 30 memset(G,0,sizeof(G)); 31 memset(G_reversal,0,sizeof(G_reversal)); 32 cin>>P>>Q; 33 for(int i=1;i<=Q;i++){ 34 int a,b,c; 35 scanf("%d%d%d",&a,&b,&c); 36 37 node.to=b; 38 node.dis_uv=c; 39 G[a].push_back(node); 40 41 node.to=a; 42 node.dis_uv=c; 43 G_reversal[b].push_back(node); 44 } 45 memset(D,0x3f,sizeof(D)); 46 D[1]=0; 47 forpair.num=1; 48 forpair.dis_from_v1=0; 49 q.push(forpair); 50 while(!q.empty()){ 51 forpair=q.top(); 52 q.pop(); 53 int u=forpair.num; 54 // cout<<"@"<<u<<endl; 55 for(int i=0;i<G[u].size();i++){//总写成i从1到G[u].size 56 int v=G[u][i].to; 57 int w=G[u][i].dis_uv; 58 // cout<<v<<endl; 59 // cout<<D[v]<<" "<<D[u]<<" "<<w<<endl; 60 if(D[v]>D[u]+w){ 61 D[v]=D[u]+w; 62 forpair.num=v; 63 forpair.dis_from_v1=D[v]; 64 q.push(forpair); 65 } 66 } 67 } 68 //cout<<D[2]<<endl; 69 memset(D_reversal,0x3f,sizeof(D_reversal)); 70 D_reversal[1]=0; 71 forpair.num=1; 72 forpair.dis_from_v1=0; 73 q.push(forpair); 74 while(!q.empty()){ 75 forpair=q.top(); 76 q.pop(); 77 int u=forpair.num; 78 for(int i=0;i<G_reversal[u].size();i++){ 79 int v=G_reversal[u][i].to; 80 int w=G_reversal[u][i].dis_uv; 81 if(D_reversal[v]>D_reversal[u]+w){ 82 D_reversal[v]=D_reversal[u]+w; 83 forpair.num=v; 84 forpair.dis_from_v1=D_reversal[v]; 85 q.push(forpair); 86 } 87 } 88 } 89 90 int min=0; 91 for(int i=1;i<=P;i++){ 92 min=min+D_reversal[i]+D[i]; 93 } 94 cout<<min<<endl; 95 } 96 } 97 }
洛谷UVA721:
要求:3.00s、0B
我的:270ms、0B、代码长度2.49KB
代码同上(vector+SPFA) —— 实际测试数据点数只有不到200000个
我的:540ms、0B
代码同上(堆优化优先队列迪杰斯特拉+vector存图+手写pair)
洛谷P1342:
要求:
我的:1.22s、89.03MB、代码长度2.37KB —— 什么玩意啊我靠!!!之前、之前也有过,看了下还有人1.91s过的(11/5号lihuanshen)
我的代码(vector存图+SPFA) —— 不同的是这个距离需要long long int类型,且点数只有不到30000个
1 #include<stdio.h> 2 #include<string.h> 3 #include<queue> 4 #include<iostream> 5 #include<vector> 6 using namespace std; 7 long long int D[1000001]; 8 long long int D_reversal[1000001]; 9 int num_of_n[1000001]; 10 int num_n; 11 struct Edge{ 12 int to; 13 int w; 14 } edge; 15 16 vector<Edge>G[1000001]; 17 vector<Edge>G_reversal[1000001]; 18 queue<int>q; 19 int main() 20 { 21 // freopen("zhishu.txt","r",stdin); 22 // int N; 23 int P,Q;//这题P没意义吧? 24 // while(scanf("%d",&N)!=EOF){ 25 while(scanf("%d%d",&P,&Q)!=EOF){ 26 num_n=0; 27 memset(G,0,sizeof(G));//忘记写了 28 memset(G_reversal,0,sizeof(G_reversal)); 29 memset(num_of_n,0,sizeof(num_of_n)); 30 // cin>>P>>Q; 31 for(int i=1;i<=Q;i++){ 32 int a,b,c; 33 scanf("%d%d%d",&a,&b,&c); 34 edge.to=b; 35 edge.w=c; 36 G[a].push_back(edge); 37 edge.to=a; 38 edge.w=c; 39 G_reversal[b].push_back(edge); 40 if(num_of_n[a]==0){ 41 num_n++; 42 num_of_n[a]=1; 43 } 44 if(num_of_n[b]==0){ 45 num_n++; 46 num_of_n[b]=1; 47 } 48 49 } 50 51 //cout<<"%"<<G[1].size()<<endl; 52 //cout<<"@"<<G_reversal[1].size()<<endl; 53 54 memset(D,0x3f,sizeof(D)); 55 q.push(1); 56 D[1]=0; 57 while(!q.empty()){ 58 int u=q.front(); 59 q.pop(); 60 for(int i=0;i<G[u].size();i++){ 61 int v=G[u][i].to; 62 int w=G[u][i].w; 63 // cout<<"#"<<u<<" "<<v<<endl; 64 if(D[v]>D[u]+w){ 65 D[v]=D[u]+w; 66 q.push(v); 67 } 68 } 69 } 70 memset(D_reversal,0x3f,sizeof(D_reversal)); 71 q.push(1); 72 D_reversal[1]=0; 73 while(!q.empty()){ 74 int u=q.front(); 75 q.pop(); 76 for(int i=0;i<G_reversal[u].size();i++){ 77 int v=G_reversal[u][i].to; 78 int w=G_reversal[u][i].w; 79 if(D_reversal[v]>D_reversal[u]+w){ 80 D_reversal[v]=D_reversal[u]+w; 81 q.push(v); 82 } 83 } 84 } 85 86 87 long long int min=0; 88 for(int i=1;i<=num_n;i++){ 89 min=min+D_reversal[i]+D[i]; 90 } 91 // cout<<min<<endl; 92 printf("%lld\n",min); 93 // } 94 } 95 }
我的:1.12s内存85.60MB
我的代码同上(堆优化优先队列迪杰斯特拉+vector存图+手写pair)
1 #include<stdio.h> 2 #include<string.h> 3 #include<queue> 4 #include<iostream> 5 #include<vector> 6 using namespace std; 7 long long int D[1000001]; 8 long long int D_reversal[1000001]; 9 struct Node{ 10 int to; 11 int dis_uv; 12 } node; 13 struct forPair{ 14 int num; 15 int dis_from_v1; 16 }forpair; 17 vector<Node>G[1000001]; 18 vector<Node>G_reversal[1000001]; 19 priority_queue<forPair>q; 20 bool operator<(forPair a,forPair b){ 21 return a.dis_from_v1>b.dis_from_v1; 22 } 23 int main() 24 { 25 // freopen("zhishu.txt","r",stdin); 26 // int N; 27 int P,Q; 28 while(cin>>P>>Q){ 29 memset(G,0,sizeof(G)); 30 memset(G_reversal,0,sizeof(G_reversal)); 31 // cin>>P>>Q; 32 for(int i=1;i<=Q;i++){ 33 int a,b,c; 34 scanf("%d%d%d",&a,&b,&c); 35 36 node.to=b; 37 node.dis_uv=c; 38 G[a].push_back(node); 39 40 node.to=a; 41 node.dis_uv=c; 42 G_reversal[b].push_back(node); 43 } 44 memset(D,0x3f,sizeof(D)); 45 D[1]=0; 46 forpair.num=1; 47 forpair.dis_from_v1=0; 48 q.push(forpair); 49 while(!q.empty()){ 50 forpair=q.top(); 51 q.pop(); 52 int u=forpair.num; 53 // cout<<"@"<<u<<endl; 54 for(int i=0;i<G[u].size();i++){//总写成i从1到G[u].size 55 int v=G[u][i].to; 56 int w=G[u][i].dis_uv; 57 // cout<<v<<endl; 58 // cout<<D[v]<<" "<<D[u]<<" "<<w<<endl; 59 if(D[v]>D[u]+w){ 60 D[v]=D[u]+w; 61 forpair.num=v; 62 forpair.dis_from_v1=D[v]; 63 q.push(forpair); 64 } 65 } 66 } 67 //cout<<D[2]<<endl; 68 memset(D_reversal,0x3f,sizeof(D_reversal)); 69 D_reversal[1]=0; 70 forpair.num=1; 71 forpair.dis_from_v1=0; 72 q.push(forpair); 73 while(!q.empty()){ 74 forpair=q.top(); 75 q.pop(); 76 int u=forpair.num; 77 for(int i=0;i<G_reversal[u].size();i++){ 78 int v=G_reversal[u][i].to; 79 int w=G_reversal[u][i].dis_uv; 80 if(D_reversal[v]>D_reversal[u]+w){ 81 D_reversal[v]=D_reversal[u]+w; 82 forpair.num=v; 83 forpair.dis_from_v1=D_reversal[v]; 84 q.push(forpair); 85 } 86 } 87 } 88 89 long long int min=0; 90 for(int i=1;i<=P;i++){ 91 min=min+D_reversal[i]+D[i]; 92 } 93 cout<<min<<endl; 94 } 95 }
POJ:
要求:8000MS、262144K
我的:106532K、7563MS
我的代码(vector存图+SPFA) —— 要用long long int存距离,且测试数据1000000个点
1 #include<stdio.h> 2 #include<string.h> 3 #include<queue> 4 #include<iostream> 5 #include<vector> 6 using namespace std; 7 long long int D[1000001]; 8 long long int D_reversal[1000001]; 9 int num_of_n[1000001]; 10 int num_n; 11 struct Edge{ 12 int to; 13 int w; 14 } edge; 15 16 vector<Edge>G[1000001]; 17 vector<Edge>G_reversal[1000001]; 18 queue<int>q; 19 int main() 20 { 21 // freopen("zhishu.txt","r",stdin); 22 int N; 23 int P,Q;//这题P没意义吧? 24 while(cin>>N){ 25 while(N--){ 26 num_n=0; 27 memset(G,0,sizeof(G));//忘记写了 28 memset(G_reversal,0,sizeof(G_reversal)); 29 memset(num_of_n,0,sizeof(num_of_n)); 30 cin>>P>>Q; 31 for(int i=1;i<=Q;i++){ 32 int a,b,c; 33 scanf("%d%d%d",&a,&b,&c); 34 35 edge.to=b; 36 edge.w=c; 37 G[a].push_back(edge); 38 edge.to=a; 39 edge.w=c; 40 G_reversal[b].push_back(edge); 41 if(num_of_n[a]==0){ 42 num_n++; 43 num_of_n[a]=1; 44 } 45 if(num_of_n[b]==0){ 46 num_n++; 47 num_of_n[b]=1; 48 } 49 50 } 51 52 //cout<<"%"<<G[1].size()<<endl; 53 //cout<<"@"<<G_reversal[1].size()<<endl; 54 55 memset(D,0x3f,sizeof(D)); 56 q.push(1); 57 D[1]=0; 58 while(!q.empty()){ 59 int u=q.front(); 60 q.pop(); 61 for(int i=0;i<G[u].size();i++){ 62 int v=G[u][i].to; 63 int w=G[u][i].w; 64 // cout<<"#"<<u<<" "<<v<<endl; 65 if(D[v]>D[u]+w){ 66 D[v]=D[u]+w; 67 q.push(v); 68 } 69 } 70 } 71 72 memset(D_reversal,0x3f,sizeof(D_reversal)); 73 q.push(1); 74 D_reversal[1]=0; 75 while(!q.empty()){ 76 int u=q.front(); 77 q.pop(); 78 for(int i=0;i<G_reversal[u].size();i++){ 79 int v=G_reversal[u][i].to; 80 int w=G_reversal[u][i].w; 81 if(D_reversal[v]>D_reversal[u]+w){ 82 D_reversal[v]=D_reversal[u]+w; 83 q.push(v); 84 } 85 } 86 } 87 88 89 long long int min=0; 90 for(int i=1;i<=num_n;i++){ 91 min=min+D_reversal[i]+D[i]; 92 } 93 cout<<min<<endl; 94 } 95 } 96 }
我的:102592K、7907MS
我的代码同上(堆优化优先队列迪杰斯特拉+vector存图+手写pair)
1 #include<stdio.h> 2 #include<string.h> 3 #include<queue> 4 #include<iostream> 5 #include<vector> 6 using namespace std; 7 long long int D[1000001]; 8 long long int D_reversal[1000001]; 9 struct Node{ 10 int to; 11 int dis_uv; 12 } node; 13 struct forPair{ 14 int num; 15 int dis_from_v1; 16 }forpair; 17 vector<Node>G[1000001]; 18 vector<Node>G_reversal[1000001]; 19 priority_queue<forPair>q; 20 bool operator<(forPair a,forPair b){ 21 return a.dis_from_v1>b.dis_from_v1; 22 } 23 int main() 24 { 25 // freopen("zhishu.txt","r",stdin); 26 int N; 27 int P,Q; 28 while(cin>>N){ 29 while(N--){ 30 memset(G,0,sizeof(G)); 31 memset(G_reversal,0,sizeof(G_reversal)); 32 cin>>P>>Q; 33 for(int i=1;i<=Q;i++){ 34 int a,b,c; 35 scanf("%d%d%d",&a,&b,&c); 36 37 node.to=b; 38 node.dis_uv=c; 39 G[a].push_back(node); 40 41 node.to=a; 42 node.dis_uv=c; 43 G_reversal[b].push_back(node); 44 } 45 memset(D,0x3f,sizeof(D)); 46 D[1]=0; 47 forpair.num=1; 48 forpair.dis_from_v1=0; 49 q.push(forpair); 50 while(!q.empty()){ 51 forpair=q.top(); 52 q.pop(); 53 int u=forpair.num; 54 // cout<<"@"<<u<<endl; 55 for(int i=0;i<G[u].size();i++){//总写成i从1到G[u].size 56 int v=G[u][i].to; 57 int w=G[u][i].dis_uv; 58 // cout<<v<<endl; 59 // cout<<D[v]<<" "<<D[u]<<" "<<w<<endl; 60 if(D[v]>D[u]+w){ 61 D[v]=D[u]+w; 62 forpair.num=v; 63 forpair.dis_from_v1=D[v]; 64 q.push(forpair); 65 } 66 } 67 } 68 //cout<<D[2]<<endl; 69 memset(D_reversal,0x3f,sizeof(D_reversal)); 70 D_reversal[1]=0; 71 forpair.num=1; 72 forpair.dis_from_v1=0; 73 q.push(forpair); 74 while(!q.empty()){ 75 forpair=q.top(); 76 q.pop(); 77 int u=forpair.num; 78 for(int i=0;i<G_reversal[u].size();i++){ 79 int v=G_reversal[u][i].to; 80 int w=G_reversal[u][i].dis_uv; 81 if(D_reversal[v]>D_reversal[u]+w){ 82 D_reversal[v]=D_reversal[u]+w; 83 forpair.num=v; 84 forpair.dis_from_v1=D_reversal[v]; 85 q.push(forpair); 86 } 87 } 88 } 89 90 long long int min=0; 91 for(int i=1;i<=P;i++){ 92 min=min+D_reversal[i]+D[i]; 93 } 94 cout<<min<<endl; 95 } 96 } 97 }
HDU:
要求:5000MS、65536K
我的:3525MS、52940K
我的代码(vector存图+SPFA) —— 开500001都MLE,我AC代码只开了300001,我开1000001结果MLE显示1232MS 65636K
1 #include<stdio.h> 2 #include<string.h> 3 #include<queue> 4 #include<iostream> 5 #include<vector> 6 using namespace std; 7 long long int D[300001]; 8 long long int D_reversal[300001]; 9 int num_of_n[300001]; 10 int num_n; 11 struct Edge{ 12 int to; 13 int w; 14 } edge; 15 16 vector<Edge>G[300001]; 17 vector<Edge>G_reversal[300001]; 18 queue<int>q; 19 int main() 20 { 21 // freopen("zhishu.txt","r",stdin); 22 int N; 23 int P,Q;//这题P没意义吧? 24 while(cin>>N){ 25 while(N--){ 26 num_n=0; 27 memset(G,0,sizeof(G));//忘记写了 28 memset(G_reversal,0,sizeof(G_reversal)); 29 memset(num_of_n,0,sizeof(num_of_n)); 30 cin>>P>>Q; 31 for(int i=1;i<=Q;i++){ 32 int a,b,c; 33 scanf("%d%d%d",&a,&b,&c); 34 35 edge.to=b; 36 edge.w=c; 37 G[a].push_back(edge); 38 edge.to=a; 39 edge.w=c; 40 G_reversal[b].push_back(edge); 41 if(num_of_n[a]==0){ 42 num_n++; 43 num_of_n[a]=1; 44 } 45 if(num_of_n[b]==0){ 46 num_n++; 47 num_of_n[b]=1; 48 } 49 50 } 51 52 //cout<<"%"<<G[1].size()<<endl; 53 //cout<<"@"<<G_reversal[1].size()<<endl; 54 55 memset(D,0x3f,sizeof(D)); 56 q.push(1); 57 D[1]=0; 58 while(!q.empty()){ 59 int u=q.front(); 60 q.pop(); 61 for(int i=0;i<G[u].size();i++){ 62 int v=G[u][i].to; 63 int w=G[u][i].w; 64 // cout<<"#"<<u<<" "<<v<<endl; 65 if(D[v]>D[u]+w){ 66 D[v]=D[u]+w; 67 q.push(v); 68 } 69 } 70 } 71 72 memset(D_reversal,0x3f,sizeof(D_reversal)); 73 q.push(1); 74 D_reversal[1]=0; 75 while(!q.empty()){ 76 int u=q.front(); 77 q.pop(); 78 for(int i=0;i<G_reversal[u].size();i++){ 79 int v=G_reversal[u][i].to; 80 int w=G_reversal[u][i].w; 81 if(D_reversal[v]>D_reversal[u]+w){ 82 D_reversal[v]=D_reversal[u]+w; 83 q.push(v); 84 } 85 } 86 } 87 88 89 long long int min=0; 90 for(int i=1;i<=num_n;i++){ 91 min=min+D_reversal[i]+D[i]; 92 } 93 cout<<min<<endl; 94 } 95 } 96 }
我的:3369MS、52456K
我的代码同上(堆优化优先队列迪杰斯特拉+vector存图+手写pair),依旧是只能开到300001
1 #include<stdio.h> 2 #include<string.h> 3 #include<queue> 4 #include<iostream> 5 #include<vector> 6 using namespace std; 7 long long int D[300001]; 8 long long int D_reversal[300001]; 9 struct Node{ 10 int to; 11 int dis_uv; 12 } node; 13 struct forPair{ 14 int num; 15 int dis_from_v1; 16 }forpair; 17 vector<Node>G[300001]; 18 vector<Node>G_reversal[300001]; 19 priority_queue<forPair>q; 20 bool operator<(forPair a,forPair b){ 21 return a.dis_from_v1>b.dis_from_v1; 22 } 23 int main() 24 { 25 // freopen("zhishu.txt","r",stdin); 26 int N; 27 int P,Q; 28 while(cin>>N){ 29 while(N--){ 30 memset(G,0,sizeof(G)); 31 memset(G_reversal,0,sizeof(G_reversal)); 32 cin>>P>>Q; 33 for(int i=1;i<=Q;i++){ 34 int a,b,c; 35 scanf("%d%d%d",&a,&b,&c); 36 37 node.to=b; 38 node.dis_uv=c; 39 G[a].push_back(node); 40 41 node.to=a; 42 node.dis_uv=c; 43 G_reversal[b].push_back(node); 44 } 45 memset(D,0x3f,sizeof(D)); 46 D[1]=0; 47 forpair.num=1; 48 forpair.dis_from_v1=0; 49 q.push(forpair); 50 while(!q.empty()){ 51 forpair=q.top(); 52 q.pop(); 53 int u=forpair.num; 54 // cout<<"@"<<u<<endl; 55 for(int i=0;i<G[u].size();i++){//总写成i从1到G[u].size 56 int v=G[u][i].to; 57 int w=G[u][i].dis_uv; 58 // cout<<v<<endl; 59 // cout<<D[v]<<" "<<D[u]<<" "<<w<<endl; 60 if(D[v]>D[u]+w){ 61 D[v]=D[u]+w; 62 forpair.num=v; 63 forpair.dis_from_v1=D[v]; 64 q.push(forpair); 65 } 66 } 67 } 68 //cout<<D[2]<<endl; 69 memset(D_reversal,0x3f,sizeof(D_reversal)); 70 D_reversal[1]=0; 71 forpair.num=1; 72 forpair.dis_from_v1=0; 73 q.push(forpair); 74 while(!q.empty()){ 75 forpair=q.top(); 76 q.pop(); 77 int u=forpair.num; 78 for(int i=0;i<G_reversal[u].size();i++){ 79 int v=G_reversal[u][i].to; 80 int w=G_reversal[u][i].dis_uv; 81 if(D_reversal[v]>D_reversal[u]+w){ 82 D_reversal[v]=D_reversal[u]+w; 83 forpair.num=v; 84 forpair.dis_from_v1=D_reversal[v]; 85 q.push(forpair); 86 } 87 } 88 } 89 90 long long int min=0; 91 for(int i=1;i<=P;i++){ 92 min=min+D_reversal[i]+D[i]; 93 } 94 cout<<min<<endl; 95 } 96 } 97 }
可用平台:
要求:3000ms、65536kB
vector存图+SPFA不行,MLE,开小了RE
-----------------------------------开始看别人代码-------------------------------------
参考一(来自POJ讨论区):dij+手搓,POJ才2.1s,仿佛山洞里捡到了武林绝世秘籍(后来知道就是邻接表)(这句话是刷这道题的时候回来更新的,发现tmd居然是链式向前星,不知不觉把这玩意给学了,那此文中所有提到的该邻接表其实都是链式向前星),关于 while(~scanf("%d",&t)) ,参考博客 (但此时POJ挂了),我是真的死轴,不用起点当vector的序号就好了
但写的还是别扭,54行我想知道uv距离依旧有点不对头,不用邻接矩阵这么难写么我靠
1 #include<stdio.h> 2 #include<string.h> 3 #include<iostream> 4 #includ<queue> 5 using namespace std; 6 struct Edge{//但迪杰斯特拉我应该存的结构体是Node啊 7 int from; 8 int to; 9 int cost; 10 int cost_from_v1; 11 }edge; 12 bool operator<(const Edge &a)const{ 13 return cost_from_v1>a.cost_from_v1; 14 } 15 int vis[1000001]; 16 int num; 17 int D[1000001]; 18 vector<Edge>G;//G应该设置一维二维纠结了一下 19 priority_queue<int>q; 20 int main() 21 { 22 int N; 23 int P,Q; 24 while(cin>>N){ 25 while(N--){ 26 memset(vis,0,sizeof(vis)); 27 memset(D,0x3f,sizeof(D)); 28 G.clear(); 29 num=0; 30 cin>>P>>Q; 31 for(int i=1;i<=Q;i++){ 32 int a,b,c; 33 cin>>a>>b>>c; 34 edge.from=a; 35 edge.to=b; 36 edge.cost=c; 37 G.push_back(edge);//用不用G[i]纠结了下 38 if(vis[a]==0){ 39 vis[a]=1; 40 num++; 41 } 42 if(vis[b]==0){ 43 vis[b]=1; 44 num++; 45 } 46 } 47 D[1]=0; 48 q.push(1);//先不想和贝尔曼的差别 49 while(!q.empty()){ 50 int u=q.front; 51 q.pop();//我觉得堆优化迪杰斯特拉不需要vis数组 52 for(int i=1;i<=num;i++){ 53 54 if(D[G[i].to]>D[u]+G[i].cost) 55 } 56 } 57 58 } 59 } 60 }
这个人的代码真的惊为天人!!!,很大胆的展示了进去过就不再进的思想,磕磕绊绊,根本看不懂,强迫自己读他的代码,理解思想,啃了2天,很有手动模拟前驱后继指针链表那些东西的味道,很像之前看到过的记录路径小技巧:其一、其二(搜“记录路径”),但更好理解更灵活
防止POJ崩溃把这人代码copy过来,POJ讨论区还有这人的SPFA不看了。看到个神乎其神的仿佛倚天剑屠龙刀降龙十八掌(都不用开数组)
1 #include<cstdio> 2 #include<queue> 3 #include<algorithm> 4 #include<cstring> 5 #define MAX 1100000 6 using namespace std; 7 int head[MAX],top; 8 int dis[MAX],vis[MAX]; 9 struct edge{ 10 int from; 11 int to; 12 int cost; 13 int next; 14 }e[MAX],save[MAX]; 15 void push_front(int from,int to,int cost) 16 { 17 top++; 18 e[top].from=from; 19 e[top].to=to; 20 e[top].cost=cost; 21 e[top].next=head[from]; 22 head[from]=top; 23 } 24 struct Node{ 25 int x; 26 int cost; 27 bool operator<(const Node &b)const 28 { 29 30 return b.cost<cost; 31 } 32 }temp,p,sta; 33 void bfs(int s) 34 { 35 sta.x=s; 36 sta.cost=0; 37 memset(vis,0,sizeof(vis)); 38 memset(dis,0,sizeof(dis)); 39 priority_queue<Node> que; 40 que.push(sta); 41 while(!que.empty()) 42 { 43 p=que.top(); 44 que.pop(); 45 if(!vis[p.x]) 46 { 47 vis[p.x]=1; 48 dis[p.x]=p.cost; 49 for(int i=head[p.x];i!=0;i=e[i].next) 50 { 51 temp.x=e[i].to; 52 if(!vis[temp.x]) 53 { 54 temp.cost=p.cost+e[i].cost; 55 que.push(temp); 56 57 } 58 } 59 } 60 } 61 // printf("%d\n",dis[en]); 62 } 63 int main() 64 { 65 int t,q,n; 66 while(~scanf("%d",&t)) 67 { 68 while(t--) 69 { 70 71 scanf("%d%d",&n,&q); 72 for(int i=1; i<=q; i++) 73 { 74 int u,v,c; 75 scanf("%d%d%d",&u,&v,&c); 76 save[i].from=u,save[i].to=v,save[i].cost=c; 77 } 78 long long ans=0; 79 ///1 80 top=0; 81 memset(head,0,sizeof(head)); 82 for(int i=1;i<=q;i++) 83 push_front(save[i].from,save[i].to,save[i].cost); 84 bfs(1); 85 for(int i=1;i<=n;i++)ans+=dis[i]; 86 ///2 87 top=0; 88 memset(head,0,sizeof(head)); 89 for(int i=1;i<=q;i++) 90 push_front(save[i].to,save[i].from,save[i].cost); 91 bfs(1); 92 for(int i=1;i<=n;i++)ans+=dis[i]; 93 94 /// 95 printf("%lld\n",ans); 96 97 98 } 99 100 } 101 return 0; 102 }
这人真的好牛逼啊,有种四两拨千斤太极拳的感觉(后来知道就是邻接表),不是一时半会能理解透的,但依旧别照着抄,每天看一看然后自己根据理解自己写,形成自己的风格,抄的话就毁了,永远有别人代码风格受束缚,很多地方会写的四不像,脑海里有别人代码的印象,自己感觉哪里写的不对又不敢改,永远打不出力道。至此POJ讨论区看完
参考二(来自SP50):真的同上,SP50题解里另外一个过于抽象略过。P1342第一个是双端队列先搁置。只有我一个人不知道这种写法么,发现P1343也有上面那样写的。至此SP50题解看完
参考三(来自P1342):终于看到跟我之前没写下去一样思路的了,这人500ms过的,发现差别就在快读上,去了快读就1.02s了(清一色快读,这题没快读,题解里所有人都超过1s)
首先证明了优先队列没必要vis,但上面的加了,待会看看咋回事,
但这个人思路证明了我当时的想法,没必要遍历所有点,那我之前的代码(以点头为序号的vector)又可以继续写了(突然发现之前邻接矩阵遍历所有点太der了,这下对迪杰斯特拉更加理解了一点,只要遍历所有有关系的就行,嘴上说着沾亲带故但一直遍历的是所有的点)。—— 迪杰斯特拉沾亲带故本身就不用遍历所有点,而贝尔曼/SPFA说是找所有点,但其实点如果都没路走个JB,所以SPFA也是遍历沾亲带故,不用所有点(这俩算法好像)
新学的内存(结合之前的10^9是1s?),2*10^4就已经是1.5G了,邻接矩阵写法的话肯定不行。
堆优化优先队列迪杰斯特拉+vector存图+手写pair(pair作为优先队列的数据类型,因为需要比较权重,在里面排列每次弹出dis_from_v1最小的。而贝尔曼/SPFA每次只要压入 int 类型顶点就行),注意,要区分开vector存图的类型和压入优先队列的类型,这俩不是一个东西(手写pair作为优先队列数据类型的这个类型是为了找顶点的,vector存图那个是为了罗列出该顶点所有的出度和距离的), 如果在vector存图的时候就存入num和dis_from_v1,那我需要事先给1出度所有点赋下值,首次找到最近的点,但其实可以只将顶点1赋值压入队列,将赋值操作放入队列比较里,之前说过。确实如之前想的需要两个结构体,之前也是,还是v8说的,想到了不管多离谱一定要写
草泥马洛谷SP50的傻逼翻译,一直说P是包含1的线路数量,发现题解有人用P来当点数,亏老子还特意搞了个num和num_n来记录点的数量,现在读了原英文才知道P就是站点的数量,简单写下一次AC,但草你奶奶我的无论提交到POJ还是SP50时间都跟SPFA差不多,为啥别人写就那么快
1 #include<stdio.h> 2 #include<string.h> 3 #include<queue> 4 #include<iostream> 5 #include<vector> 6 using namespace std; 7 int D[1000001]; 8 int D_reversal[1000001]; 9 struct Node{ 10 int to; 11 int dis_uv; 12 } node; 13 struct forPair{ 14 int num; 15 int dis_from_v1; 16 }forpair; 17 vector<Node>G[1000001]; 18 vector<Node>G_reversal[1000001]; 19 priority_queue<forPair>q; 20 bool operator<(forPair a,forPair b){ 21 return a.dis_from_v1>b.dis_from_v1; 22 } 23 int main() 24 { 25 // freopen("zhishu.txt","r",stdin); 26 int N; 27 int P,Q; 28 while(cin>>N){ 29 while(N--){ 30 memset(G,0,sizeof(G)); 31 memset(G_reversal,0,sizeof(G_reversal)); 32 cin>>P>>Q; 33 for(int i=1;i<=Q;i++){ 34 int a,b,c; 35 scanf("%d%d%d",&a,&b,&c); 36 37 node.to=b; 38 node.dis_uv=c; 39 G[a].push_back(node); 40 41 node.to=a; 42 node.dis_uv=c; 43 G_reversal[b].push_back(node); 44 } 45 memset(D,0x3f,sizeof(D)); 46 D[1]=0; 47 forpair.num=1; 48 forpair.dis_from_v1=0; 49 q.push(forpair); 50 while(!q.empty()){ 51 forpair=q.top(); 52 q.pop(); 53 int u=forpair.num; 54 // cout<<"@"<<u<<endl; 55 for(int i=0;i<G[u].size();i++){//总写成i从1到G[u].size 56 int v=G[u][i].to; 57 int w=G[u][i].dis_uv; 58 // cout<<v<<endl; 59 // cout<<D[v]<<" "<<D[u]<<" "<<w<<endl; 60 if(D[v]>D[u]+w){ 61 D[v]=D[u]+w; 62 forpair.num=v; 63 forpair.dis_from_v1=D[v]; 64 q.push(forpair); 65 } 66 } 67 } 68 //cout<<D[2]<<endl; 69 memset(D_reversal,0x3f,sizeof(D_reversal)); 70 D_reversal[1]=0; 71 forpair.num=1; 72 forpair.dis_from_v1=0; 73 q.push(forpair); 74 while(!q.empty()){ 75 forpair=q.top(); 76 q.pop(); 77 int u=forpair.num; 78 for(int i=0;i<G_reversal[u].size();i++){ 79 int v=G_reversal[u][i].to; 80 int w=G_reversal[u][i].dis_uv; 81 if(D_reversal[v]>D_reversal[u]+w){ 82 D_reversal[v]=D_reversal[u]+w; 83 forpair.num=v; 84 forpair.dis_from_v1=D_reversal[v]; 85 q.push(forpair); 86 } 87 } 88 } 89 90 int min=0; 91 for(int i=1;i<=P;i++){ 92 min=min+D_reversal[i]+D[i]; 93 } 94 cout<<min<<endl; 95 } 96 } 97 }
简单了解了下他代码里的pair。至此P1342题解看完
UVA721题解没有先玩意,也看完
参考四(来自HDU):
发现有人1s过了,百度找题解,看到个不错的大佬博客(这人看他好几篇博客了),这人的邻接表跟之前遇到的所有人的都不一样,最离奇的是,将maxn缩小,改为我的300001居然TLE,好奇试了下,将maxn改为2000000居然tm也才4s,这个邻接表是点越多越快吗????
由此可见,hdu数据好弱,应该来一个10^6数量级的点,
适当的多多看别人的代码真的有好处,发现现在只要搂一眼就可以知道他用的是什么算法什么思路了,这在之前是想都不敢想的技能
发现无论是SPFA还是迪杰斯特拉,时间都差不多,但邻接表要比vector快好多好多,而当数据很大的时候,邻接矩阵连编译都过不了。还有快读也是个很牛逼的神器。
所以快读+邻接表真的是最短路问题的独孤九剑,邻接表的弊病
更新:发现邻接表仅仅是个下品神器,只有当范围很大的时候用
难度解析:
至此感觉UVA721数据最弱,理由AC居然0B,然后是SP50,然后P1342,都属于地平线以下的玩意(第一次这么水),然后是北大POJ(第一次这么牛),POJ数据给满了10^6,时限也很大,很朴素。
然后杭电HDU题目范围给的很好,但数据有点瘸腿太水了,卡了内存,没卡点,用vector开5*10^5 MLE,想提示我们用邻接表,但后台测试数据没跟上,直接开少点3*10^5就可以用vectorAC了,可用平台就牛逼了,10^6MLE,开少了直接RE很完美。即点数增多了,变稀疏图,更适合用邻接表
但想个事,为何大佬博客邻接表开5*10^5个点HDU反而TLE,开10^6就AC。vector开5*10^5就可以过,开10^6就MLE。
将大佬博客提交到POJ1.8s
1 #include<stdio.h> 2 #include<iostream> 3 #include<algorithm> 4 #include<string.h> 5 #include<queue> 6 using namespace std; 7 const int maxn=1000005;//邻接表数组 8 //const int INF=99999999;//正无穷 9 int u[maxn]; 10 int v[maxn]; 11 int w[maxn]; 12 int first[maxn]; 13 int nextn[maxn];//以上用于邻接表 14 long long int dis[maxn];//存储1到各点或者各点到1的最短距离 15 int vis[maxn];//已访问标记为1,初始化为0 16 int P;//P个站点 17 int Q;//Q条路线 18 void init()//邻接表建图 19 { 20 for(int i=0; i<=Q; i++) //初始化邻接表数组 21 first[i]=nextn[i]=-1; 22 for(int i=0; i<Q; i++) 23 { 24 scanf("%d%d%d",&u[i],&v[i],&w[i]); 25 nextn[i]=first[u[i]]; 26 first[u[i]]=i; 27 } 28 } 29 void set_init()//邻接表反向建图 30 { 31 for(int i=0; i<=Q; i++) 32 first[i]=nextn[i]=-1; 33 for(int i=0; i<Q; i++) 34 { 35 nextn[i]=first[v[i]]; 36 first[v[i]]=i; 37 } 38 } 39 void SPFA(int point,int flag) 40 { 41 //flag为1时,dis记录point到各点最短距离。 42 //flag为0时,dis记录各点到point的最短距离 43 for(int i=0;i<=P;i++) 44 { 45 vis[i]=0;//初始化为未访问 46 } 47 memset(dis,0x3f,sizeof(dis)); 48 // dis[i]=INF;//point到各点距离初始化为正无穷 49 dis[point]=0;//自己到自己的距离为0 50 queue<int>q;//创建队列q 51 q.push(point);//起始结点入队 52 while(!q.empty()) 53 { 54 point=q.front();//赋值给point只是为了减少变量 55 q.pop(); 56 vis[point]=0;//先标记为未访问 57 for(int k=first[point];k!=-1;k=nextn[k]) 58 { 59 int temp=(flag?v[k]:u[k]);//求point到各点或者各点到point 60 if(dis[temp]>dis[point]+w[k])//松弛各边 61 { 62 dis[temp]=dis[point]+w[k]; 63 if(vis[temp]==0)//如果未访问 64 { 65 vis[temp]=1;//标记为已访问 66 q.push(temp);//结点入队 67 } 68 } 69 } 70 } 71 } 72 int main() 73 { 74 int T;//T组数据 75 scanf("%d",&T); 76 while(T--) 77 { 78 scanf("%d%d",&P,&Q); 79 init();//邻接表建图 80 SPFA(1,1); 81 long long int sum=0;//记录总路程 82 for(int i=2;i<=P;i++) 83 sum+=dis[i]; 84 set_init();//反向建图 85 SPFA(1,0); 86 for(int i=2;i<=P;i++) 87 sum+=dis[i]; 88 printf("%lld\n",sum); 89 } 90 }
加个快读900ms
1 #include<ctype.h> 2 #include<stdio.h> 3 #include<iostream> 4 #include<algorithm> 5 #include<string.h> 6 #include<queue> 7 using namespace std; 8 const int maxn=1000005;//邻接表数组 9 const int INF=99999999;//正无穷 10 int u[maxn]; 11 int v[maxn]; 12 int w[maxn]; 13 int first[maxn]; 14 int nextn[maxn];//以上用于邻接表 15 long long int dis[maxn];//存储1到各点或者各点到1的最短距离 16 int vis[maxn];//已访问标记为1,初始化为0 17 int P;//P个站点 18 int Q;//Q条路线 19 inline int read() { 20 int x = 0, f = 1; 21 char ch = getchar(); 22 if(ch==EOF)return 0; 23 while (!isdigit(ch)) { 24 if (ch == '-') f = -1; 25 ch = getchar(); 26 } 27 while (isdigit(ch)) { 28 x = x * 10 + ch - 48; 29 ch = getchar(); 30 } 31 return x * f; 32 } 33 void init()//邻接表建图 34 { 35 for(int i=0; i<=Q; i++) //初始化邻接表数组 36 first[i]=nextn[i]=-1; 37 for(int i=0; i<Q; i++) 38 { 39 u[i]=read(); 40 v[i]=read(); 41 w[i]=read(); 42 // scanf("%d%d%d",&u[i],&v[i],&w[i]); 43 nextn[i]=first[u[i]]; 44 first[u[i]]=i; 45 } 46 } 47 void set_init()//邻接表反向建图 48 { 49 for(int i=0; i<=Q; i++) 50 first[i]=nextn[i]=-1; 51 for(int i=0; i<Q; i++) 52 { 53 nextn[i]=first[v[i]]; 54 first[v[i]]=i; 55 } 56 } 57 void SPFA(int point,int flag) 58 { 59 //flag为1时,dis记录point到各点最短距离。 60 //flag为0时,dis记录各点到point的最短距离 61 for(int i=0;i<=P;i++) 62 { 63 vis[i]=0;//初始化为未访问 64 } 65 memset(dis,0x3f,sizeof(dis)); 66 // dis[i]=INF;//point到各点距离初始化为正无穷 67 dis[point]=0;//自己到自己的距离为0 68 queue<int>q;//创建队列q 69 q.push(point);//起始结点入队 70 while(!q.empty()) 71 { 72 point=q.front();//赋值给point只是为了减少变量 73 q.pop(); 74 vis[point]=0;//先标记为未访问 75 for(int k=first[point];k!=-1;k=nextn[k]) 76 { 77 int temp=(flag?v[k]:u[k]);//求point到各点或者各点到point 78 if(dis[temp]>dis[point]+w[k])//松弛各边 79 { 80 dis[temp]=dis[point]+w[k]; 81 if(vis[temp]==0)//如果未访问 82 { 83 vis[temp]=1;//标记为已访问 84 q.push(temp);//结点入队 85 } 86 } 87 } 88 } 89 } 90 int main() 91 { 92 int T;//T组数据 93 while(T=read()) 94 while(T--) 95 { 96 P=read(); 97 Q=read(); 98 // scanf("%d%d",&P,&Q); 99 init();//邻接表建图 100 SPFA(1,1); 101 long long int sum=0;//记录总路程 102 for(int i=2;i<=P;i++) 103 sum+=dis[i]; 104 set_init();//反向建图 105 SPFA(1,0); 106 for(int i=2;i<=P;i++) 107 sum+=dis[i]; 108 printf("%lld\n",sum); 109 } 110 }
但为何HDU还是4s —— 加个快读2s
1 #include<ctype.h> 2 #include<stdio.h> 3 #include<iostream> 4 #include<algorithm> 5 #include<string.h> 6 #include<queue> 7 using namespace std; 8 const int maxn=1000005;//邻接表数组 9 const int INF=99999999;//正无穷 10 int u[maxn]; 11 int v[maxn]; 12 int w[maxn]; 13 int first[maxn]; 14 int nextn[maxn];//以上用于邻接表 15 int dis[maxn];//存储1到各点或者各点到1的最短距离 16 int vis[maxn];//已访问标记为1,初始化为0 17 int P;//P个站点 18 int Q;//Q条路线 19 inline int read() { 20 int x = 0, f = 1; 21 char ch = getchar(); 22 if(ch==EOF)return 0; 23 while (!isdigit(ch)) { 24 if (ch == '-') f = -1; 25 ch = getchar(); 26 } 27 while (isdigit(ch)) { 28 x = x * 10 + ch - 48; 29 ch = getchar(); 30 } 31 return x * f; 32 } 33 void init()//邻接表建图 34 { 35 for(int i=0; i<=Q; i++) //初始化邻接表数组 36 first[i]=nextn[i]=-1; 37 for(int i=0; i<Q; i++) 38 { 39 u[i]=read(); 40 v[i]=read(); 41 w[i]=read(); 42 // scanf("%d%d%d",&u[i],&v[i],&w[i]); 43 nextn[i]=first[u[i]]; 44 first[u[i]]=i; 45 } 46 } 47 void set_init()//邻接表反向建图 48 { 49 for(int i=0; i<=Q; i++) 50 first[i]=nextn[i]=-1; 51 for(int i=0; i<Q; i++) 52 { 53 nextn[i]=first[v[i]]; 54 first[v[i]]=i; 55 } 56 } 57 void SPFA(int point,int flag) 58 { 59 //flag为1时,dis记录point到各点最短距离。 60 //flag为0时,dis记录各点到point的最短距离 61 for(int i=0;i<=P;i++) 62 { 63 vis[i]=0;//初始化为未访问 64 dis[i]=INF;//point到各点距离初始化为正无穷 65 } 66 dis[point]=0;//自己到自己的距离为0 67 queue<int>q;//创建队列q 68 q.push(point);//起始结点入队 69 while(!q.empty()) 70 { 71 point=q.front();//赋值给point只是为了减少变量 72 q.pop(); 73 vis[point]=0;//先标记为未访问 74 for(int k=first[point];k!=-1;k=nextn[k]) 75 { 76 int temp=(flag?v[k]:u[k]);//求point到各点或者各点到point 77 if(dis[temp]>dis[point]+w[k])//松弛各边 78 { 79 dis[temp]=dis[point]+w[k]; 80 if(vis[temp]==0)//如果未访问 81 { 82 vis[temp]=1;//标记为已访问 83 q.push(temp);//结点入队 84 } 85 } 86 } 87 } 88 } 89 int main() 90 { 91 int T;//T组数据 92 while(T=read()) 93 while(T--) 94 { 95 P=read(); 96 Q=read(); 97 // scanf("%d%d",&P,&Q); 98 init();//邻接表建图 99 SPFA(1,1); 100 int sum=0;//记录总路程 101 for(int i=2;i<=P;i++) 102 sum+=dis[i]; 103 set_init();//反向建图 104 SPFA(1,0); 105 for(int i=2;i<=P;i++) 106 sum+=dis[i]; 107 printf("%d\n",sum); 108 } 109 }
提交到SP50 110ms、24M —— 改成SP50的25000,甚至增到50000都提示RE,提交到UVA721的200000却可以AC
提交到P1342 1.1s,29M(提交记录里460ms第一名,是快读+邻接表)
再把POJ讨论区手搓那人的代码POJ 2.1s —— 加快读POJ变成1.1s
提交到HDU 3.6s —— 加个快读就1.3s、50M了,但300001依旧离奇的TLE,改成600001提示 Runtime Error (ACCESS_VIOLATION)
1 #include<cstdio> 2 #include<queue> 3 #include<ctype.h> 4 #include<algorithm> 5 #include<cstring> 6 #define MAX 1100000 7 using namespace std; 8 int head[MAX],top; 9 int dis[MAX],vis[MAX]; 10 struct edge{ 11 int from; 12 int to; 13 int cost; 14 int next; 15 }e[MAX],save[MAX]; 16 inline int read() { 17 int x = 0, f = 1; 18 char ch = getchar(); 19 if(ch==EOF)return 0; 20 while (!isdigit(ch)) { 21 if (ch == '-') f = -1; 22 ch = getchar(); 23 } 24 while (isdigit(ch)) { 25 x = x * 10 + ch - 48; 26 ch = getchar(); 27 } 28 return x * f; 29 } 30 void push_front(int from,int to,int cost) 31 { 32 top++; 33 e[top].from=from; 34 e[top].to=to; 35 e[top].cost=cost; 36 e[top].next=head[from]; 37 head[from]=top; 38 } 39 struct Node{ 40 int x; 41 int cost; 42 bool operator<(const Node &b)const 43 { 44 45 return b.cost<cost; 46 } 47 }temp,p,sta; 48 void bfs(int s) 49 { 50 sta.x=s; 51 sta.cost=0; 52 memset(vis,0,sizeof(vis)); 53 memset(dis,0,sizeof(dis)); 54 priority_queue<Node> que; 55 que.push(sta); 56 while(!que.empty()) 57 { 58 p=que.top(); 59 que.pop(); 60 if(!vis[p.x]) 61 { 62 vis[p.x]=1; 63 dis[p.x]=p.cost; 64 for(int i=head[p.x];i!=0;i=e[i].next) 65 { 66 temp.x=e[i].to; 67 if(!vis[temp.x]) 68 { 69 temp.cost=p.cost+e[i].cost; 70 que.push(temp); 71 72 } 73 } 74 } 75 } 76 // printf("%d\n",dis[en]); 77 } 78 int main() 79 { 80 81 int t,q,n; 82 // t=read(); 83 while(t=read()) 84 { 85 while(t--) 86 { 87 88 // scanf("%d%d",&n,&q); 89 n=read();q=read(); 90 for(int i=1; i<=q; i++) 91 { 92 int u,v,c; 93 // scanf("%d%d%d",&u,&v,&c); 94 u=read(); 95 v=read(); 96 c=read(); 97 save[i].from=u,save[i].to=v,save[i].cost=c; 98 } 99 long long ans=0; 100 ///1 101 top=0; 102 memset(head,0,sizeof(head)); 103 for(int i=1;i<=q;i++) 104 push_front(save[i].from,save[i].to,save[i].cost); 105 bfs(1); 106 for(int i=1;i<=n;i++)ans+=dis[i]; 107 ///2 108 top=0; 109 memset(head,0,sizeof(head)); 110 for(int i=1;i<=q;i++) 111 push_front(save[i].to,save[i].from,save[i].cost); 112 bfs(1); 113 for(int i=1;i<=n;i++)ans+=dis[i]; 114 115 /// 116 printf("%lld\n",ans); 117 118 119 } 120 121 } 122 return 0; 123 }
SP50 280ms —— 加了快读100ms,但改成25000依旧离奇RE
发现洛谷和HDU(时限5s,无快读都是4s),时间少的都是快读,邻接表和vector差别不明显
POJ邻接表比vector快很多,加快读又快很多,但都不是极致,并不是提交排行榜最快的
至此几个问题(随时更新)
0、上面优先队列没必要vis那个
1、为何数组开的越少越不对劲,甚至TLE,开大了才能AC好奇怪(已解决)
2、HDU没找到时间少的代码
3、可用平台没AC
4、return和return 0(int函数里包括main都要有值,即return 0)(已解决)
5、邻接表缺点,如果重复边咋办(这题如果有重复边不完犊子WA了??)—— 你妈的我还以为多大个缺点,一直查邻接表怎么解决重边,结果自己试了下(就下面收代码里的那组数据,加一个2 6 2),发现可以存储三条2出发的边。想来说的可能是输入边如果完全一样会徒增不必要的复杂度,呵呵,邻接表优化的这么牛逼,多存几个重复边能咋的?就好像说给有反弹能力的九阳神功加一个开战前让敌人先出两次手的这个副作用。(已解决)
ACwing早有耳闻第一次用,相当牛逼的网站,学了下邻接表
给他收个尾
1 #include<iostream> 2 using namespace std; 3 int e[100]; 4 int w[100]; 5 int ne[100]; 6 int h[100]; 7 int idx; 8 void add(int a,int b,int c) 9 { 10 e[idx]=b; 11 w[idx]=c; 12 ne[idx]=h[a]; 13 h[a]=idx; //h初始为空(-1) 14 // idx++; //初始为0 15 return; 16 } 17 int a,b,c; 18 int main() 19 { 20 int p,q; 21 cin>>p>>q; 22 23 for(int i=0;i<100;i++) 24 h[i]=-1; 25 for(int i=0;i<q;i++){ 26 27 cin>>a>>b>>c; 28 add(a,b,c); 29 printf("@ e[%d]:%d w[%d]:%d ne[%d]:%d h[%d]:%d\n",idx,e[idx],idx,w[idx],idx,ne[idx],a,h[a]); 30 idx++; 31 cout<<endl; 32 } 33 } 34 //6 7 35 //1 2 2 36 //1 5 1 37 //3 1 4 38 //2 4 3 39 //1 3 7 40 //2 6 1 41 //4 6 5
怎么应用参照POJ手搓那人的代码里的这句 for(int i=head[p.x];i!=0;i=e[i].next) temp.x=e[i].to; 即可
想遍历某个点所有沾亲带故的点,比如1点,
h数组记录了边信息的下标,用这个下标去e和w数组里找,由于要找1出发的点都有哪些,即松弛沾亲带故的那步,那就h[1],发现是4,这个4就是下标,去e[4]和w[4]数组里找,1 3 7找到一个,然后ne数组记录了下一个1开头的边,ne[4]是1,这个1就是边信息的下标,此时下标为1,(小说明:h[1]已经是4了,这个ne[4]的1来自于之前的h[1],然后h[1]就被赋值为4了,所以不能再看h了),就直接用这个下标1去e,w里找,1 5 1又找到一个,然后ne数组记录了下一个1开头的边,ne[1]是0,0就是下一个点1开头的下标,这个0来自于上一次的h[1],he[1]把0赋值给ne[1],然后就被赋予了新值1,所以依旧不用看h数组,直接用这个0下标去e,w里找信息,1 2 2 又得到一个边,然后是-1结束。这个-1结束还是0结束,值来自于ne数组,但ne数组值来自h数组,所以全看h开始怎么初始化。
所以说其实h数组的唯一作用就是作为鞭炮的那个捻儿或者说导火线,即经过多次输入后,记录了最后一次给某点赋值的信息,进一步说就是比如想找顶点2出发的路都有那些,那h[2]的值5,就记录了最后一次输的信息,称之为下标,e和w数组用这个5下标找到信息,ne数组用5下标找到下一个信息,就OK了。
至此只能粗浅的理解怎么应用,ACwing里那个博客写的相当深奥(虽然博主已经写的相当浅显易懂了),许多东西暂时无法理解透彻,
大佬博客(SPFA)写的不好理解(更新:发现就是问号冒号语法,真牛逼,将2遍SPFA合成一个来写,待会学下),把手搓那人的代码当作自己邻接表迪杰斯特拉的模板(依旧是自己看懂后,不再看,自己写)
每次学东西都要自己充当大和尚小和尚来回跑,学新东西好费劲。
啃手搓哥代码的时候,cnm,为啥TLE的答案呼之欲出!!踏破铁鞋无觅处
上面控制台输出的那个图依旧有用,我用的代码
1 #include<iostream> 2 #define MAX 2 3 using namespace std; 4 int e[MAX]; 5 int w[MAX]; 6 int ne[MAX]; 7 int h[MAX]; 8 int idx; 9 void add(int a,int b,int c) 10 { 11 e[idx]=b; 12 w[idx]=c; 13 ne[idx]=h[a]; 14 cout<<"add函数里的idx:"<<idx<<endl; 15 h[a]=idx; //h初始为空(-1) 16 // idx++; //初始为0 17 return; 18 } 19 int a,b,c; 20 int main() 21 { 22 // freopen("zhishu.txt","r",stdin); 23 int p,q; 24 cin>>p>>q; 25 26 for(int i=0;i<MAX;i++) 27 h[i]=-1; 28 for(int i=0;i<q;i++){ 29 cin>>a>>b>>c; 30 // cout<<"!"<<h[3]<<endl;//发现未定义的h[3]在for外是0在这里每次都不一样 31 add(a,b,c); 32 printf("@ e[%d]:%d w[%d]:%d ne[%d]:%d h[%d]:%d\n",idx,e[idx],idx,w[idx],idx,ne[idx],a,h[a]); 33 idx++; 34 cout<<"&"<<idx<<endl; 35 cout<<endl; 36 } 37 } 38 //6 7 39 //1 2 2 40 //1 5 1 41 //3 1 4 42 //2 4 3 43 //1 3 7 44 //2 6 1 45 //4 6 5
0、“给他收个尾”代码里的30行代码未定义的h[3]在for外是0,在for这里每次都不一样(当然这不是主要的问题)
1、我测试发现点总共没有10^6那么多就把最大值都改成了相应点的,但邻接表那个下标是边数,“给他收个尾”代码里的11、12行,所以上面用别人邻接表代码改到测试数据需要的点数了也会RE,因为访问的是边(这个依旧不是重点)
2、我发现只要开小了啥问题都有,输入1 3 7数据那,已经 idx++ 了变为4了,到函数里居然从4变到了3(这个也不是重点)
3、重点来了:开的不够不仅加一了的idx会变的不可预测,输入2 4 3那,ne[3]用的是h[2],h[2]没赋值导致随机,弄成了3,这会导致程序一直循环在迪杰斯特拉沾亲带故松弛遍历那句,即下一条边一直是这条边。随意就算赋值的时候10^6数据量都赋值初始化,由于边数未知也无法将10^6缩小一丝一毫
好开心!
照着上面“给他收个尾”那里的控制台的图,来写代码(方便想每个数组意义和赋值逻辑),
草泥马吓老子一跳博客园加载贼慢,一直记住密码的提示登陆身份信息失效或注销,差点以为文章写太长把博客园写崩溃了,以为被博客园给销号了md
写完代码编译不过,几个问题:
1、next不能做变量名字,洛谷博客(那句“全机房貌似就我不知道”好可爱),参考博客、参考博客、参考博客(里面提到的郭炜老师C语言挺有名,还有个郝斌貌似)
2、百度有个AI绿色头像的叫技术大牛(牛逼),国内的这些傻逼噱头AI都想直接用Adblock顺手屏蔽了,结果
真他妈惊到我了(虽然不完全对但帮我找了很多错误和讲解也不错),之前听公众号说GPT可以写算法题,现在感觉真牛逼,第一次用这玩意。之前都是百度智能回答来搜报错信息挺好。(上次王Y涵说用GPT找bug我以为ppt他吼哈哈)
哎调试半天总出错,POJ又崩溃了
好挣扎好崩溃,HDU和洛谷都能AC,POJ和可用平台WA (POJ这么出彩么,都跟可用平台并驾齐驱了)—— 虽然WA但里面的注释相当相当值得看,都是踩过的坑
1 #include<stdio.h> 2 #include<string.h> 3 #include<iostream> 4 #include<queue> 5 #define MAX 1100001 6 using namespace std; 7 int to[MAX]; 8 int cost[MAX]; 9 int nex[MAX]; 10 int head[MAX]; 11 int idx; 12 long long int D[MAX]; 13 long long int D_reverse[MAX]; 14 struct Edge{ 15 int from; 16 int to; 17 int cost; 18 }edge[MAX]; 19 struct Node{ 20 int num; 21 long long int cost_from_v1;//大坑,一开始只把俩D数组和minD弄long了 22 }node; 23 void add(int a,int b,int c) 24 { 25 to[idx]=b; 26 cost[idx]=c; 27 nex[idx]=head[a];//head下标写错了一开始 28 // cout<<"函数里idx"<<idx<<endl; 29 head[a]=idx; 30 // idx++; 31 } 32 bool operator<(Node a ,Node b){ 33 return a.cost_from_v1>b.cost_from_v1; 34 } 35 priority_queue<Node>q; 36 void dijkstra(int positive_or_reverse); 37 int main() 38 { 39 // freopen("zhishu.txt","r",stdin); 40 int n; 41 int p,q; 42 int a,b,c; 43 while(scanf("%d",&n)!=EOF){ 44 while(n--){ 45 // while(!q.empty())//没必要清空,但发现int q和queue的q重了,幸好是在局部内定义的int q,下次注意 46 // q.pop(); 47 idx=0;//很重要,不然idx会一直增下去,出现注入to[idx]idx超过10^6情况,导致RE 48 // cin>>p>>q; 49 scanf("%d%d",&p,&q); 50 for(int i=0;i<q;i++){ 51 scanf("%d%d%d",&a,&b,&c); 52 edge[i].from=a; 53 edge[i].to=b; 54 edge[i].cost=c; 55 } 56 // 正迪杰斯特拉 57 // to、cost、nex都会重新赋值,不必初始化。q队列初始化为空,每次跑也是empty了才结束,也不用管清空的事情 58 for(int i=0;i<q;i++) 59 head[i]=-1; 60 memset(D,0x3f,sizeof(D)); 61 for(int i=0;i<q;i++){ 62 add(edge[i].from,edge[i].to,edge[i].cost); 63 //printf("to[%d]:%d cost[%d]:%d nex[%d]:%d head[%d]:%d\n",idx,to[idx],idx,cost[idx],idx,nex[idx],edge[i].from,head[edge[i].from]); 64 idx++; 65 } 66 dijkstra(0);//此时D[i]存了1到i点的最短距离 67 // cout<<"#"<<endl; 68 idx=0;//很重要,不然会RE 69 //cout<<"#"<<idx<<endl; 70 71 //反迪杰斯特拉 72 for(int i=0;i<q;i++) 73 head[i]=-1; 74 memset(D_reverse,0x3f,sizeof(D_reverse)); 75 for(int i=0;i<q;i++){ 76 add(edge[i].to,edge[i].from,edge[i].cost); 77 //printf("to[%d]:%d cost[%d]:%d nex[%d]:%d head[%d]:%d\n",idx,to[idx],idx,cost[idx],idx,nex[idx],edge[i].from,head[edge[i].from]); 78 idx++; 79 } 80 dijkstra(1); 81 //cout<<D_reverse[2]<<endl; 82 long long int minD=0; 83 for(int i=1;i<=p;i++)//一开始写成了q 84 minD=minD+D[i]+D_reverse[i]; 85 // cout<<minD<<endl; 86 printf("%lld\n",minD);//没\n会WA 87 } 88 } 89 } 90 void dijkstra(int positive_or_reverse) 91 { 92 if(positive_or_reverse==0) 93 D[1]=0; 94 if(positive_or_reverse==1) 95 D_reverse[1]=0; 96 node.num=1; 97 node.cost_from_v1=0; 98 q.push(node); 99 while(!q.empty()){ 100 // cout<<"*"<<endl; 101 node=q.top(); 102 int num=node.num; 103 // long long int thiscost=node.cost_from_v1;//大坑,一开始只把两个D数组和minD弄long了,忘记这个了WA好几次 104 q.pop(); 105 // cout<<"&"<<num<<endl; 106 for(int i=head[num];i!=-1;i=nex[i]){//限制条件写错了一开始,nex下标也写错了一开始 107 if(positive_or_reverse==0){ 108 if(D[to[i]]>D[num]+cost[i]){//D下标写错了一开始 109 D[to[i]]=D[num]+cost[i]; 110 node.cost_from_v1=D[to[i]]; 111 node.num=to[i]; 112 q.push(node); 113 // cout<<D[to[i]]<<" i:"<<i<<endl; 114 } 115 // cout<<"this"<<endl; 116 } 117 if(positive_or_reverse==1){ 118 if(D_reverse[to[i]]>D_reverse[num]+cost[i]){ 119 D_reverse[to[i]]=D_reverse[num]+cost[i]; 120 node.cost_from_v1=D_reverse[to[i]]; 121 node.num=to[i]; 122 q.push(node); 123 // cout<<D_reverse[to[i]]<<" "<<to[i]<<endl; 124 } 125 } 126 } 127 // cout<<"!"<<endl; 128 } 129 }
(没啥用的小发现:看手搓那人AC代码发现其实 cost_from_v1 和 D[] 都不用long long int,1点到某点和某点到1点都是int,唯独累和的时候才long)
无奈对拍,麻痹的弄死我得了,对拍数据还不好生成,因为要保证每个点都可以到1,1可以去每个点。只有增大边数,来增加可以到每个点的可能
对拍代码
1 #include <iostream> 2 #include <stdlib.h> 3 #include <time.h> 4 #include<stdio.h> 5 #include<iostream> 6 #include<time.h> 7 #include <string> 8 #include <random> 9 using namespace std; 10 int a,b,c; 11 int main(){ 12 srand(time(0) + (unsigned long long)(new char)); 13 int n=1; 14 cout<<n<<endl; 15 for(int i=1;i<=n;i++){ 16 int p = rand()%5+1; 17 int q = rand()%1000+1; 18 cout<<p<<" "<<q<<endl; 19 for(int i=0;i<q;i++){ 20 while(a= rand()%p+1){ 21 if(a<=p) 22 break; 23 } 24 while(b=rand()%p+1){ 25 if(a<=p) 26 break; 27 } 28 int c = rand()%30+1; 29 cout<<a<<" "<<b<<" "<<c<<endl; 30 } 31 32 33 } 34 }
也没啥错误
唉,这道题搞了整整三天,值不值得?
一步步对比手搓代码,开始用百度技术大牛的GPT(名字起的有点像个垃圾假货),发现真的嘎嘎好用诶,查了下 bool operator<(const Node &b)const ,回答的不错
麻痹的改到凌晨3点,终于发现问题了,由于对拍数据不好生成, 直接把手搓哥的代码每个功能模块都改成我的代码思路去写,
1 #include<cstdio> 2 #include<iostream> 3 #include<queue> 4 #include<algorithm> 5 #include<cstring> 6 #define MAX 1000001 7 using namespace std; 8 int head[MAX],top; 9 int dis[MAX],vis[MAX]; 10 struct edge{ 11 int from; 12 int to; 13 int cost; 14 int next; 15 }e[MAX],save[MAX]; 16 int D[MAX]; 17 int D_re[MAX]; 18 void push_front(int from,int to,int cost) 19 { 20 e[top].to=to; 21 e[top].cost=cost; 22 e[top].next=head[from]; 23 head[from]=top; 24 // top++; 25 } 26 struct Node{ 27 int x; 28 int cost; 29 // bool operator<(const Node &b)const 30 // return b.cost<cost; 31 // 32 33 }temp,p,sta; 34 bool operator<(Node a ,Node b){ 35 return a.cost>b.cost; 36 } 37 void bfs(int s) 38 { 39 if(s==0) 40 D[1]=0; 41 if(s==1) 42 D_re[1]=0; 43 sta.x=1; 44 sta.cost=0; 45 D[1]=0; 46 priority_queue<Node> que; 47 que.push(sta); 48 while(!que.empty()) 49 { 50 p=que.top(); 51 que.pop(); 52 for(int i=head[p.x];i!=-1;i=e[i].next) 53 { 54 temp.x=e[i].to; 55 if(s==0) 56 if(D[temp.x]>D[p.x]+e[i].cost){ 57 D[temp.x]=D[p.x]+e[i].cost; 58 temp.cost=D[temp.x]; 59 que.push(temp); 60 } 61 if(s==1) 62 if(D_re[temp.x]>D_re[p.x]+e[i].cost){ 63 D_re[temp.x]=D_re[p.x]+e[i].cost; 64 temp.cost=D_re[temp.x]; 65 que.push(temp); 66 } 67 68 } 69 } 70 } 71 int main() 72 { 73 int t,q,n; 74 while(~scanf("%d",&t)) 75 { 76 while(t--) 77 { 78 79 scanf("%d%d",&n,&q); 80 for(int i=0; i<q; i++) 81 { 82 int u,v,c; 83 scanf("%d%d%d",&u,&v,&c); 84 save[i].from=u,save[i].to=v,save[i].cost=c; 85 } 86 87 top=0; 88 // memset(head,-1,sizeof(head)); 89 for(int i=1;i<=q;i++) 90 head[i]=-1; 91 memset(D,0x3f,sizeof(D)); 92 // memset(D_re,0x3f,sizeof(D_re)); 93 for(int i=0;i<q;i++){ 94 push_front(save[i].from,save[i].to,save[i].cost); 95 //printf("e[%d].to:%d e[%d].cost:%d e[%d].next:%d head[%d]:%d\n", 96 // top,e[top].to,top,e[top].cost,top,e[top].next,save[i].from,head[save[i].from]); 97 top++; 98 } 99 bfs(0); 100 101 top=0; 102 for(int i=1;i<=q;i++) 103 head[i]=-1; 104 memset(head,-1,sizeof(head)); 105 // memset(D,0x3f,sizeof(D)); 106 memset(D_re,0x3f,sizeof(D_re)); 107 for(int i=0;i<q;i++){ 108 push_front(save[i].to,save[i].from,save[i].cost); 109 top++; 110 } 111 bfs(1); 112 113 long long ans=0; 114 for(int i=1;i<=n;i++) 115 ans+=D[i]+D_re[i]; 116 117 printf("%lld\n",ans); 118 119 120 } 121 122 } 123 }
最后发现是head数组的问题,首先要知道memset -1由于巧合,依旧是-1,这种错误或笔误的用法,反倒可以AC,而我知道这一点所以用for赋值-1的,又因为我不想无脑开那么大,导致错过一些小细节,比如这次,我如果给head的整个MAX数量级的数组都赋值为-1,那也不会出现这个问题,虽然WA的很崩溃挣扎煎熬,但真的学到的细节的东西(更加理解了head数组在写的时候下标真正需要多少),我一开始怀疑过head赋值这个问题,思考后觉得没问题就略过了,我以为0到q-1作为下标每次 add函数 输入边信息,那head也应该是0到q-1。但都打印出来就知道了,head应该是点数的范围,1到p
小总结,但其实刚刚拿手搓哥代码做改动AC的代码里写的是1~边数q,POJ就AC了,但应该是1~点数p,而最开始HDU和洛谷都AC的是0~边数q-1(只要点数比边数多就可看出问题,数据可真水,不对啊,点数怎么可能比边数多),但想想发现,点数必定少于边数啊,最多持平,俩点俩边,那POJ WA了head的0~边数q-1,q就AC了咋回事,那就是说q-1比点q少,q比点数多或者正好,那应该就是点数和边数持平,那测试下 2 2 2 1 2 13 2 1 33 明显出现了问题,上是0~q-1的,下是0~q的
这个是正好再到2并没更短也就没更新,持平的例子还有很多,只要是一圈n个点n个边就行,构造一下就可以卡掉0~q-1的了
至此我的代码也AC了
好坎坷。可用平台也AC了,至此六大平台均已AC。
AC代码 —— 六大平台均能AC
1 #include<stdio.h> 2 #include<string.h> 3 #include<iostream> 4 #include<queue> 5 #define MAX 1000001 6 using namespace std; 7 int to[MAX]; 8 int cost[MAX]; 9 int nex[MAX]; 10 int head[MAX]; 11 int idx; 12 int D[MAX]; 13 int D_reverse[MAX]; 14 struct Edge{ 15 int from; 16 int to; 17 int cost; 18 }edge[MAX]; 19 struct Node{ 20 int num; 21 int cost_from_v1; 22 }node; 23 void add(int a,int b,int c) 24 { 25 to[idx]=b; 26 cost[idx]=c; 27 nex[idx]=head[a]; 28 head[a]=idx; 29 idx++; 30 } 31 bool operator<(Node a ,Node b){ 32 return a.cost_from_v1>b.cost_from_v1; 33 } 34 priority_queue<Node>q; 35 void dijkstra(int positive_or_reverse); 36 int main() 37 { 38 // freopen("zhishu.txt","r",stdin); 39 int n; 40 int p,q; 41 int a,b,c; 42 while(scanf("%d",&n)!=EOF){ 43 while(n--){ 44 idx=0; 45 scanf("%d%d",&p,&q); 46 for(int i=0;i<q;i++){ 47 scanf("%d%d%d",&a,&b,&c); 48 edge[i].from=a; 49 edge[i].to=b; 50 edge[i].cost=c; 51 } 52 // 正迪 53 for(int i=1;i<=p;i++) 54 head[i]=-1; 55 memset(D,0x3f,sizeof(D)); 56 for(int i=0;i<q;i++){ 57 add(edge[i].from,edge[i].to,edge[i].cost); 58 // idx++; 59 } 60 dijkstra(0); 61 62 idx=0; 63 // 反迪 64 for(int i=1;i<=p;i++) 65 head[i]=-1; 66 memset(D_reverse,0x3f,sizeof(D_reverse)); 67 for(int i=0;i<q;i++){ 68 add(edge[i].to,edge[i].from,edge[i].cost); 69 // idx++; 70 } 71 dijkstra(1); 72 long long int minD=0; 73 for(int i=2;i<=p;i++) 74 minD=minD+D[i]+D_reverse[i]; 75 printf("%lld\n",minD); 76 } 77 } 78 } 79 void dijkstra(int positive_or_reverse) 80 { 81 if(positive_or_reverse==0) 82 D[1]=0; 83 if(positive_or_reverse==1) 84 D_reverse[1]=0; 85 node.num=1; 86 node.cost_from_v1=0; 87 q.push(node); 88 while(!q.empty()){ 89 node=q.top(); 90 int num=node.num; 91 q.pop(); 92 for(int i=head[num];i!=-1;i=nex[i]){ 93 if(positive_or_reverse==0){ 94 if(D[to[i]]>D[num]+cost[i]){ 95 D[to[i]]=D[num]+cost[i]; 96 node.cost_from_v1=D[to[i]]; 97 node.num=to[i]; 98 q.push(node); 99 } 100 } 101 if(positive_or_reverse==1){ 102 if(D_reverse[to[i]]>D_reverse[num]+cost[i]){ 103 D_reverse[to[i]]=D_reverse[num]+cost[i]; 104 node.cost_from_v1=D_reverse[to[i]]; 105 node.num=to[i]; 106 q.push(node); 107 } 108 } 109 } 110 } 111 }
加个快读(快读只在AC后爽爽,不然很有误导性,学不到东西)
1 #include<ctype.h>//给isdigit用的 2 #include<stdio.h> 3 #include<string.h> 4 #include<iostream> 5 #include<queue> 6 #define MAX 1000001 7 using namespace std; 8 int to[MAX]; 9 int cost[MAX]; 10 int nex[MAX]; 11 int head[MAX]; 12 int idx; 13 int D[MAX]; 14 int D_reverse[MAX]; 15 16 inline int read() { 17 int x = 0, f = 1; 18 char ch = getchar(); 19 if(ch==EOF)return 0; 20 while (!isdigit(ch)) { 21 if (ch == '-') f = -1; 22 ch = getchar(); 23 } 24 while (isdigit(ch)) { 25 x = x * 10 + ch - 48; 26 ch = getchar(); 27 } 28 return x * f; 29 } 30 31 struct Edge{ 32 int from; 33 int to; 34 int cost; 35 }edge[MAX]; 36 struct Node{ 37 int num; 38 int cost_from_v1; 39 }node; 40 void add(int a,int b,int c) 41 { 42 to[idx]=b; 43 cost[idx]=c; 44 nex[idx]=head[a]; 45 head[a]=idx; 46 idx++; 47 } 48 bool operator<(Node a ,Node b){ 49 return a.cost_from_v1>b.cost_from_v1; 50 } 51 priority_queue<Node>q; 52 void dijkstra(int positive_or_reverse); 53 int main() 54 { 55 // freopen("zhishu.txt","r",stdin); 56 int n; 57 int p,q; 58 int a,b,c; 59 // while(scanf("%d",&n)!=EOF){ 60 n=read(); 61 { 62 63 while(n--){ 64 idx=0; 65 p=read(); 66 q=read(); 67 // scanf("%d%d",&p,&q); 68 for(int i=0;i<q;i++){ 69 a=read(); 70 b=read(); 71 c=read(); 72 // scanf("%d%d%d",&a,&b,&c); 73 edge[i].from=a; 74 edge[i].to=b; 75 edge[i].cost=c; 76 } 77 // 正迪 78 for(int i=1;i<=p;i++) 79 head[i]=-1; 80 memset(D,0x3f,sizeof(D)); 81 for(int i=0;i<q;i++){ 82 add(edge[i].from,edge[i].to,edge[i].cost); 83 // idx++; 84 } 85 dijkstra(0); 86 87 idx=0; 88 // 反迪 89 for(int i=1;i<=p;i++) 90 head[i]=-1; 91 memset(D_reverse,0x3f,sizeof(D_reverse)); 92 for(int i=0;i<q;i++){ 93 add(edge[i].to,edge[i].from,edge[i].cost); 94 // idx++; 95 } 96 dijkstra(1); 97 long long int minD=0; 98 for(int i=2;i<=p;i++) 99 minD=minD+D[i]+D_reverse[i]; 100 printf("%lld\n",minD); 101 } 102 } 103 } 104 void dijkstra(int positive_or_reverse) 105 { 106 if(positive_or_reverse==0) 107 D[1]=0; 108 if(positive_or_reverse==1) 109 D_reverse[1]=0; 110 node.num=1; 111 node.cost_from_v1=0; 112 q.push(node); 113 while(!q.empty()){ 114 node=q.top(); 115 int num=node.num; 116 q.pop(); 117 for(int i=head[num];i!=-1;i=nex[i]){ 118 if(positive_or_reverse==0){ 119 if(D[to[i]]>D[num]+cost[i]){ 120 D[to[i]]=D[num]+cost[i]; 121 node.cost_from_v1=D[to[i]]; 122 node.num=to[i]; 123 q.push(node); 124 } 125 } 126 if(positive_or_reverse==1){ 127 if(D_reverse[to[i]]>D_reverse[num]+cost[i]){ 128 D_reverse[to[i]]=D_reverse[num]+cost[i]; 129 node.cost_from_v1=D_reverse[to[i]]; 130 node.num=to[i]; 131 q.push(node); 132 } 133 } 134 } 135 } 136 }
改到了4点,得了,也不用导管子了,洗洗睡吧,之前一天导好几管子,最近刷题都没空导了,再刷几天都不会导了
简单看了下手搓哥的vis,没啥太大区别,不想看了,只想记住我的代码思想和风格逻辑
大佬博客那个也不错,我写的时候有点那个味道
踩过的坑:
###:回顾了下log底数,这些人一知半解怎么敢面试的啊,我tm正常轨迹都是微软谷歌选手,参考博客
###:这题起初是蓝题(提高+/省选−),现在降到黄了(普及/提高−)
###:迪杰斯特拉和DFS真的是最难的东西,BFS和SPFA都很有套路容易弄
###:就彻底啥也不会了,有机会一定把剩下的题刷完
###:最短路专题poj好像数据没那么弱
###:没有我西工大教练姜学峰搞不到的题,西安培训不泄题不透题的亚洲区域赛数一巨巨
###:前半生都tm撸管子去了,感觉刚发现很多有趣的事,倚天屠龙
###:KM和MB
###:记得POJ和HDU用C++出现一些CE错误,后来一律用G++提交了
###:回顾了用 const int maxn=25000; 和 #define MAX 1100000 ,测试点数的时候,一直傻乎乎的改好几次数组范围。
###:电脑又开始3F0了,放电一直不行,把后面夹开瓢的按一按(二哥摔暖气后面一次,我摔家里地上一次比较狠,图书馆安检机夹出问题),再长按本想再试试,结果灯亮起,直接hp界面好了。常用的时候很少3F0了,chrome也没在闪退过
###:hdu快读反而慢?根据参考自己做了改动自己的快读模板,可以Ctrl+Z结束的。输入的时候直接while(n=read())即可。注意:此文中的快读模板有问题,详见博客(这句话是刷并查集食物链题目时发现后更新的)
1 #include<ctype.h>//给isdigit用的 2 inline int read() { 3 int x = 0, f = 1; 4 char ch = getchar(); 5 if(ch==EOF)return 0; 6 while (!isdigit(ch)) { 7 if (ch == '-') f = -1; 8 ch = getchar(); 9 } 10 while (isdigit(ch)) { 11 x = x * 10 + ch - 48; 12 ch = getchar(); 13 } 14 return x * f; 15 }
三种输入写法都可以,EOF结束
1 int main() 2 { 3 int n; 4 while(n=read()){} 5 // while(cin>>n){} 6 //while(scanf("%d",&n)!=EOF){} 7 }
有关“返回值”
###:还是别加快读,错误算法(本身可能TLE的)容易被误导AC,学不到真东西
###:
为什么图书馆看到穿靴子的有种想舔的冲动。杨笠,姜萍。一直喷她俩,看本人后发现挺好的俩人。一直喷傻逼百度文心一言,一用技术大牛的gpt发现也真不错。起码有能学到东西。当你撸管子的时候别人在刷题,楼教主军训回来累了跟室友说我去切两道题放松下。真佩服BUPT19考研那个本科做了很多项目自己租服务器,初试270复试第一的“标题党”,机试就复习一星期,机试100分,空中楼阁架空学习能力我真的没有,那些人连控制台复制都不会,说一定能扛起大旗,说老师被自己的气场所震慑。。
###:memset记得是逐字节赋值,-1还是-1是巧合
###:开始习惯用百度技术大牛GPT,
目前搜资料的网站:百度,必应,百度文心GPT,ACwing,还有中学生oi科普 (懒得开tizi)