题意:n个点,电车从A到B。每个点可以到其它ki个点,但默认只通往给出的第一个点,如果要到其它点,必须改变轨道方向一次。问A到B最少改变几次轨道方向。
总结:裸裸的最短路,所以,狠狠的把Floyd, Bellman, Dijkstra, Spfa都给撸了一遍。一个字,爽!
// POJ-1847 //#include<bits/stdc++.h> #include<iostream> #include<cstdio> #include<cstdlib> #include<algorithm> #include<cstring> #include<string> #include<cmath> #include<queue> #include<stack> #include<map> #include<bitset> #include<vector> #include<set> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") #define F(i,a,b) for (int i=a;i<b;i++) #define FF(i,a,b) for (int i=a;i<=b;i++) #define mes(a,b) memset(a,b,sizeof(a)) #define INF 0x3f3f3f3f typedef long long ll; const int N = 200; int n, A, B; int G[N][N]; void Floyd() //O(V^3),任意两点间 { FF(k,1,n) FF(i,1,n) FF(j,1,n) { G[i][j] = min( G[i][j], G[i][k]+G[k][j] ); } if(G[A][B]==INF) puts("-1"); else printf("%d ", G[A][B]); } int Q[N*N], dis[N], vis[N]; //Q队列要多开 void Spfa() //O(kE),k<=2,改进的Bellman,单源,可有负权,可判负环,但感觉有时候有点玄 { mes(vis, 0); mes(dis, INF); int head=0, tail=1; Q[head]=A, dis[A]=0; while(head < tail) { int u=Q[head]; vis[u]=1; FF(i,1,n) { if(G[u][i]!=INF && dis[i]> dis[u]+G[u][i]) { //G[u][i]!=INF表示e(u,i)这条边存在,也可用个flag[][]数组标记它是否存在 dis[i]= dis[u]+G[u][i]; if(vis[i]==0) { //要判断,因为i这个点如果取过,有可能会再次取到它 vis[i]=1, Q[tail++]=i; } } } vis[u]=0, head++; //vis[u]还要变回0,所以可以重复取到这个点 } if(dis[B]==INF) puts("-1"); else printf("%d ", dis[B]); } int tot; struct Edge { int u, v, w; } edge[N*N]; void Bellman() //O(V*E),单源,可有负权,可判负环,但效率非常低 { mes(dis, INF); dis[A]=0; while(true) { bool update = false; F(i,0,tot) { Edge e=edge[i]; if(dis[e.v]> dis[e.u]+e.w) { dis[e.v]= dis[e.u]+e.w; update=true; } } if(update==false) break; //如果不能再松驰就跳出 } if(dis[B]==INF) puts("-1"); else printf("%d ", dis[B]); } int find_min() //找到dis(A, i)最小的点 { int minn=INF, pos=-1; FF(i,1,n) if(vis[i]==0 && dis[i]<minn) { pos=i, minn=dis[i]; } return pos; } void Dijkstra1() //单源,不能有负权,不优化O(V^2) { mes(vis, 0); mes(dis, INF); dis[A]=0; int p=find_min(); while(p!=-1) { vis[p]=1; FF(i,1,n) if(vis[i]==0 && dis[i]> dis[p]+G[p][i]) { dis[i]= dis[p]+G[p][i]; } p=find_min(); } if(dis[B]==INF) puts("-1"); else printf("%d ", dis[B]); } struct Node { int d, id; bool friend operator < (const Node &a, const Node &b) { return a.d > b.d; } }; void Dijkstra() //优先队列优化O(Elog(V)) { mes(vis, 0); mes(dis, INF); dis[A]=0; priority_queue<Node > PQ; PQ.push( (Node){0, A} ); while(!PQ.empty()) { Node pos=PQ.top(); PQ.pop(); if(vis[pos.id]==1) continue; //有可能被压入多次,第一次是最小的,后面的就不用再重复计算了 vis[pos.id]=1; FF(i,1,n) if(vis[i]==0) { if(dis[i] > dis[pos.id]+G[pos.id][i]) { dis[i]= dis[pos.id]+G[pos.id][i]; PQ.push( (Node){dis[i], i} ); } } } if(dis[B]==INF) puts("-1"); else printf("%d ", dis[B]); } int main() { int ki, c; mes(G, INF); tot=0; scanf("%d%d%d", &n, &A, &B); FF(i,1,n) { scanf("%d", &ki); FF(j,1,ki) { scanf("%d", &c); if(j==1) G[i][c]=0, edge[tot].w=0; else G[i][c]=1, edge[tot].w=1; edge[tot].u=i, edge[tot++].v=c; } } //Floyd(); //Spfa(); //Bellman(); //Dijkstra1(); Dijkstra(); return 0; }