【最短路】解题报告

来源:互联网 发布:微信小程序需要域名吗 编辑:程序博客网 时间:2024/06/05 08:43

4.最短路(path.c/cpp)

[问题描述]

给定一个包含N个点,M条边的无向图,每条边的边权均为1。

再给定K个三元组(A,B,C),表示从A点走到B点后不能往C点走。注意三元组是有序的,如可以从B点走到A点再走到C。

现在你要在K个三元组的限制下,找出1号点到N号点的最短路径,并输出任意一条合法路径,会有Check检查你的输出。

[输入格式]

输入文件第一行有三个数N,M,K,意义如题目所述。

接下来M行每行两个数A,B,表示A,B间有一条边。

再下面K行,每行三个数(A,B,C)描述一个三元组。

[输出格式]

输出文件共两行数,第一行一个数S表示最短路径长度。

第二行S+1个数,表示从1到N所经过的节点。

[样例输入]

4 4 2

1 2

2 3

3 4

1 3

1 2 3

1 3 4

[样例输出]

4

1 3 2 3 4

[数据范围]

对于40%的数据满足N≤10,M≤20,K≤5。

对于100%的数据满足N≤3000,M≤20000,K≤100000。

 


这道题是一道拆点的题,不过也可以用广搜来做,每次记录父亲就行了。

一开始我就卡在了这点上,走到下一个点,但是并不知道这个状态是由哪一个父亲派生出来的,但是其实就是这么简单,对每个队列中的元素都记录父亲。


广搜:

#include <cstdio>struct node{long y;long z;node* next;};node* g[3002][3002];long n;long m;long k;long que[1100000];long que2[1100000];long fa[3002];bool map[3002][3002];void insert(long x,long z,long y){node* tmp = new node;tmp -> z = z;tmp -> y = y;tmp -> next = g[x][y];g[x][y] = tmp;}void output(long p){if (fa[p]==0){printf("%ld ",que[p]);return;}output(fa[p]);printf("%ld ",que[p]);}bool check(long a,long b){node* ths = g[fa[a]][b];while (ths){if (ths->z==a) return false;ths = ths->next;}return true;}void bfs(){long l= 0;long r= 0;r++;que[r] = 1;while (l<r){long now = que[++l];for (long i=1;i<n+1;i++){if (now == i)continue;if (map[now][i]&&check(l,i)){map[now][i] = false;r++;fa[r] = l;que[r] = i;que2[r] = que2[l]+1; if (i==n){printf("%ld\n",que2[r]);output(r);return;}}}}}int main(){freopen("path.in","r",stdin);freopen("path.out","w",stdout);scanf("%ld%ld%ld",&n,&m,&k);for (long i=1;i<m+1;i++){long a;long b;scanf("%ld%ld",&a,&b);map[a][b] = true;map[b][a] = true;}for (long i=1;i<k+1;i++){long a;long b;long c;scanf("%ld%ld%ld",&a,&b,&c);insert(a,b,c);}bfs(); return 0;}


spfa+拆点

意思容易理解,只是代码不好写,因为结构体太多了。容易混淆

拆点关键就在于,对于hash、dist、还有记录方案的g统统都要增加一维。

上个方案的bfs中,hash增加了一维也是基于这个原因,因为不能从上一个点到这个点来了,但是还会有其他的路到这个点来

#include <cstdio>struct node{long z;node* next;};node* g[3002][3002];struct node1{long index;node1* next;};struct tnode{long f;long i;};long n;long m;long k;tnode que[100000];bool map[3002][3002];node1* dian[3002];bool used[3002][3002];long dist[3002][3002];long fangan[3002][3002];void insert1(long x,long y){node1* tmp = new node1;tmp->index = y;tmp->next = dian[x];dian[x] = tmp;}void insert(long x,long y,long z){node* tmp = new node;tmp -> z = z;tmp -> next = g[x][y];g[x][y] = tmp;}bool can(long a,long b,long c){node* ths = g[a][b];while (ths){if (ths->z==c) return false;ths = ths->next;}return true;}void spfa(){for (long i=0;i<n+1;i++){for (long j=0;j<n+1;j++){dist[i][j] = 0x7fff0000;}}used[1][1] = true;dist[1][1] = 0;long l = 0;long r = 1;que[r].f=1;que[r].i=1;while (l<r){l++;tnode now = que[l];used[now.f][now.i] = false;node1* ths = dian[now.i];while (ths){if (can(now.f,now.i,ths->index)&&dist[now.i][ths->index]>dist[now.f][now.i]+1){dist[now.i][ths->index]=dist[now.f][now.i]+1;fangan[now.i][ths->index] = l;if (!used[now.i][ths->index]){used[now.i][ths->index] = true;r++;que[r].i = ths->index;que[r].f = now.i;}}ths = ths -> next;}}}void output(long a,long b){if(b==1){printf("1 ");return;}tnode* la = &que[fangan[a][b]];output(la->f,la->i);printf("%ld ",b);}int main(){freopen("path.in","r",stdin);freopen("path.out","w",stdout);scanf("%ld%ld%ld",&n,&m,&k);for (long i=1;i<m+1;i++){long a;long b;scanf("%ld%ld",&a,&b);insert1(a,b);insert1(b,a);}for (long i=1;i<k+1;i++){long a;long b;long c;scanf("%ld%ld%ld",&a,&b,&c);insert(a,b,c);}spfa();long ans = 0x7fff0000;long t = 0;  for (long i=1;i<n;i++)  {if (dist[i][n]<ans)  {    ans=dist[i][n];    t=i;}}  printf("%ld\n",ans);  output(t,n);return 0;}


原创粉丝点击