三进制状压。调了一整天,一开始用记忆化搜索一直超时,后来改成了递推,代码能力真是弱。。
后来瓜神提供了一个思路,如果建立一个超级源点然后用记忆化搜索的话,应该可以过。。。。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <map>
#include <set>
#include <vector>
#include <string>
#include <queue>
#include <deque>
#include <bitset>
#include <list>
#include <cstdlib>
#include <climits>
#include <cmath>
#include <ctime>
#include <algorithm>
#include <stack>
#include <sstream>
#include <numeric>
#include <fstream>
#include <functional>
using namespace std;
#define MP make_pair
#define PB push_back
typedef long long LL;
typedef unsigned long long ULL;
typedef vector<int> VI;
typedef pair<int,int> pii;
const int INF = INT_MAX / 2;
const double eps = 1e-8;
const LL LINF = 1e17;
const double DINF = 1e60;
const int maxn = 12;
const int maxs = 59049;
const int p3[maxn] = {1,3,9,27,81,243,729,2187,6561,19683,59049};
int n,m,dist[maxn][maxn];
int f[maxn][maxs + maxn];
int st[maxs + maxn][maxn];
bool sok[maxs + maxn][maxn];
inline void expand(int st,int *arr) {
int pos = 0;
while(st) {
arr[pos++] = st % 3; st /= 3;
}
}
inline bool ok(int s,int t) {
for(int i = 0;i < t;i++)
if(st[s][i] == 0) return false;
return true;
}
int main() {
for(int i = 0;i <= maxs;i++) expand(i,st[i]);
for(int i = 0;i <= maxs;i++) {
for(int j = 0;j <= 10;j++) sok[i][j] = ok(i,j);
}
while(~scanf("%d%d",&n,&m)) {
memset(dist,-1,sizeof(dist));
for(int i = 0;i < m;i++) {
int u,v,w; scanf("%d%d%d",&u,&v,&w); u--; v--;
dist[u][v] = dist[v][u] = (
dist[u][v] == -1 ? w : min(dist[u][v],w));
}
for(int i = 0;i < n;i++)
for(int j = 0;j < p3[n];j++)
f[i][j] = INF;
int ans = INF;
for(int i = 0;i < n;i++) f[i][p3[i]] = 0;
for(int j = 0;j < p3[n];j++) {
for(int i = 0;i < n;i++) if(f[i][j] < INF) {
for(int k = 0;k < n;k++) if(dist[k][i] != -1 && st[j][k] < 2) {
f[k][j + p3[k]] = min(f[k][j + p3[k]],f[i][j] + dist[k][i]);
}
}
}
for(int i = 0;i < n;i++) {
for(int j = 0;j < p3[n];j++) {
if(sok[j][n]) {
ans = min(ans,f[i][j]);
}
}
}
if(ans >= INF) puts("-1");
else printf("%d\n",ans);
}
return 0;
}