题意:有n个点(n<=10),要求都经过,每个点最多经过两次,求遍历每个点的最小花费。
分析:每个点最多经过两次,则用三进制保存状态,一个好的技巧就是开个pos数组,记录每个状态用三进制表示时,每一位的情况。 枚举每个点为起点,然后每次sum值是不需要清空的,清空了反而造成了诸多重复遍历....................
#include <cstdio> #include <iostream> #include <cstring> #include <cmath> #define INF 0x7FFFFFFF using namespace std; int p[11]; int pos[60000][11]; int dist[11][11],sum[11][60000]; struct node { int x,buff; } q[1111111]; int head,tail,n,m,ans; void init() { for(int i=1; i<=10; i++) for(int j=1; j<=10; j++) if(i != j) dist[i][j] = INF; else dist[i][j] = 0; memset(sum,0,sizeof(sum)); } void bfs(int v0) { ans = INF; // memset(sum,0,sizeof(sum)); head = 0; tail = 0; q[head].x = v0; q[head++].buff = p[v0-1]; while(head != tail) { node t = q[tail ++]; node tt; int cnt = 0; for(int i=0; i<=n; i++) { if(pos[t.buff][i] >= 1) cnt++; } if(cnt == n) { ans = min(ans,sum[t.x][t.buff]); } for(int i=1; i<=n; i++) { if(t.x == i || dist[t.x][i] == INF) continue; if(pos[t.buff][i-1] >= 2) continue; if(sum[t.x][t.buff] + dist[t.x][i] >= ans) continue; tt.buff = t.buff + p[i-1]; tt.x = i; if(sum[i][tt.buff] != 0 && sum[i][tt.buff] > sum[t.x][t.buff] + dist[t.x][i]) { sum[i][tt.buff] = sum[t.x][t.buff] + dist[t.x][i]; q[head++] = tt; } else if(! sum[i][tt.buff]) { sum[i][tt.buff] = sum[t.x][t.buff] + dist[t.x][i]; q[head++] = tt; } } } } int main() { int a,b,c; for(int i=1; i<=11; i++) p[i-1] = pow(3.0,(i-1)*1.0); for(int i=1; i<=59050; i++) { int tmp = i,j = 0; while(tmp) { pos[i][j++] = tmp % 3; tmp = tmp / 3; } } while(scanf("%d%d",&n,&m) != EOF) { init(); for(int i=0; i<m; i++) { scanf("%d%d%d",&a,&b,&c); if(c < dist[a][b]) { dist[a][b] = c; dist[b][a] = c; } } int minn = INF; for(int i=1; i<=n; i++) { bfs(i); minn = min(minn,ans); } if(minn == INF) printf("-1\n"); else printf("%d\n",minn); } return 0; }