这题答案就是 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;
}