这题答案就是 min(1~n最短路, 包含1的最小环+包含n的最小环). (最小环不包括自环).
这题没什么, 就是求最小环的时候要注意下.
1/ 如果用邻接表, 那dist数组初始化肯定是INF, 但注意dist[st] 还是初始化为0. 不然之后无法拓展其他点. 然后在relax的时候 另外加一句 if(v==st) circle = min(circle, dist[u]+a[e].w); 就可以了. circle就是求出的包含起点的最小环.
2/ 如果用的是邻接阵, 那dist数组可能会被初始化为 W[st][i]. 那就不是从st开始拓展了, 所以 dist[st]初始化为INF. 另外如果是写成只relax !vis[v]的话. 注意不要把 vis[st] 设为1. 这样就回不到st了.
代码:
1/ 过加强数据
#include<cstdio> #include<cstring> #include<iostream> #include<cmath> #include<string> #include<vector> #include<map> #include<algorithm> using namespace std; inline int Rint() { int x; scanf("%d", &x); return x; } inline int max(int x, int y) { return (x>y)? x: y; } inline int min(int x, int y) { return (x<y)? x: y; } #define FOR(i, a, b) for(int i=(a); i<=(b); i++) #define FORD(i,a,b) for(int i=(a);i>=(b);i--) #define REP(x) for(int i=0; i<(x); i++) typedef long long int64; #define INF (1<<30) const double eps = 1e-8; #define bug(s) cout<<#s<<"="<<s<<" " #define MAXN 302 #define MAXM MAXN*MAXN struct node { int u, v, w; }a[MAXM]; //边集 int idx; int head[MAXN], next[MAXM]; void init() { memset(head, -1, sizeof(head)); idx=0;} void addedge(int u,int v, int w){ a[idx].u=u; a[idx].v=v;a[idx].w=w; next[idx]=head[u];head[u]=idx++;} int n, m; int dist[MAXN]; //st->i int ins[MAXN]; int circle; void dij(int st) { memset(ins, 0, sizeof(ins)); FOR(i, 1, n) { dist[i] = i==st? 0: INF; } while(1) { int u = -1; int mind = INF; FOR(i, 1, n) if(!ins[i]) //找不在S中的 最小 dist[u] { if(mind>dist[i]) mind=dist[i], u=i; } if(u==-1) break; ins[u] = 1; for(int e=head[u]; e!=-1; e=next[e]) //relax 邻边 { int v = a[e].v; dist[v] = min(dist[v], dist[u]+a[e].w); if(v == st) { //bug(u);bug(v)<<endl; circle = min(circle, dist[u]+a[e].w); // 不能写成 circle = min(circle, dist[v]); 因为 dist[st]始终为0 } } } } int main() { while(scanf("%d", &n)!=-1) { init(); FOR(i, 1, n) FOR(j, 1, n) { int w=Rint(); if(i==j) continue; addedge(i, j, w); } circle = INF; dij(1); //int d11 = dist[0]; int d1n = dist[n]; int d11 = circle; circle = INF; dij(n); //int dnn = dist[n-1]; //bug(d11);bug(dnn);bug(d1n)<<endl; //bug(d1n);bug(circle)<<endl; int minx = min(d1n, d11+circle); printf("%d\n", minx); } }
2/ 比赛AC, 赛后改了求最小环, 过加强数据
#include<cstdio> #include<cstring> #include<iostream> #include<cmath> #include<string> #include<vector> #include<algorithm> using namespace std; inline int Rint() { int x; scanf("%d", &x); return x; } inline int max(int x, int y) { return (x>y)? x: y; } inline int min(int x, int y) { return (x<y)? x: y; } #define FOR(i, a, b) for(int i=(a); i<=(b); i++) #define FORD(i,a,b) for(int i=(a);i>=(b);i--) #define REP(x) for(int i=0; i<(x); i++) typedef long long int64; #define INF (1<<30) const double eps = 1e-8; #define bug(s) cout<<#s<<"="<<s<<" " int map[305][305]; int n; const int MAX=302; //#define INTMax 1<<30 int v[MAX]; int d[MAX]; int dijkstra(int s) { int i,j; for(i=1;i<=n;i++) { d[i]= i==s? INF: map[s][i]; //d[i]= map[s][i]; } //v[s]=1; //for(i=1;i<n;i++) while(1) { int now=-1,min=INF; for(j=1;j<=n;j++) { if(!v[j]&&min>d[j]) { min=d[j]; now=j; } } if(now == -1) break; v[now]=1; for(j=1;j<=n;j++) if(!v[j]&&d[now]+map[now][j]<d[j]) d[j]=d[now]+map[now][j]; } return 0; } int main() { while(scanf("%d",&n)==1) { int i,j; for(i=1;i<=n;i++) { for(j=1;j<=n;j++) { cin>>map[i][j]; } } memset(d,0,sizeof(d)); memset(v,0,sizeof(v)); dijkstra(1); int d11=d[1]; int d1n=d[n]; memset(d,0,sizeof(d)); memset(v,0,sizeof(v)); dijkstra(n); int dnn=d[n]; //bug(d11);bug(dnn);bug(d1n)<<endl; int loop = d11+dnn; //bug(d1n);bug(loop)<<endl; if(d11+dnn <0) loop = INF; //bug(d1n);bug(loop)<<endl; if(loop<d1n)cout<<loop<<endl; else cout<<d1n<<endl; } return 0; }