1 3 2 1 2 2 1 3 3
10
状态压缩,16位每位上为1表示已走,0表示没有走过,直接用位运算,表示所有的状态。
dp[i][j] 状态为i,最后一次是j的最小值,则由dp[i][j] + land[k][j] 推出dp[t][k] ,t表示,i把第k位置1的数。有2 ^ 16 * n个状态,n种转移,所以复杂度为o(2^16 * n * n);
第一种方法用spaf来解。
#define N 20 #define M 100005 #define maxn 205 #define MOD 1000000007 int n,land[N][N],T,m,a,b,c,dp[M][N],all,t; queue<pii> q; bool vis[M][N]; int main() { //freopen("in.txt", "r", stdin); //freopen("out.txt", "w", stdout); while(S(T)!=EOF) { while(T--){ S2(n,m); FI(n+1) FJ(n+1) land[i][j] = MOD,vis[i][j] = false; FI(n+1) land[i][i] = 0; all = 1<<n; FI(m){ scan_d(a);scan_d(b);scan_d(c); a--;b--; land[a][b] = min(land[a][b],c); land[b][a] = land[a][b]; } For(i,0,all){ For(j,0,n){ dp[i][j] = MOD; } } dp[1][0] = 0; vis[1][0] = true; q.push(mp(1,0)); while(!q.empty()){ pii top = q.front(); q.pop(); int i = top.first,j = top.second; vis[i][j] = false; For(k,0,n) { //printf("%d %d %d\n",j,k,land[j][k]); if(land[j][k] < 300){ if(!(i & (1<<k))) t = i ^ (1<<k); else t = i; if(dp[i][j] + land[j][k] < dp[t][k]){ dp[t][k] = dp[i][j] + land[j][k]; if(!vis[t][k]) { q.push(mp(t,k)); vis[t][k] = true; //printf("%d %d %d %d %d %d %d\n",t,k,i,j,dp[t][k],dp[i][j],land[j][k]); } } } } } printf("%d\n",dp[all-1][0]); } } //fclose(stdin); //fclose(stdout); return 0; }
第二种方法,用Floyed来解,由于n很小,可以很快处理出来。
#define N 20 #define M 100005 #define maxn 205 #define MOD 1000000007 int n,land[N][N],T,m,a,b,c,dp[M][N],all,t; queue<pii> q; bool vis[M][N]; int main() { //freopen("in.txt", "r", stdin); //freopen("out.txt", "w", stdout); while(S(T)!=EOF) { while(T--){ S2(n,m); FI(n+1) FJ(n+1) land[i][j] = MOD,vis[i][j] = false; FI(n+1) land[i][i] = 0; all = 1<<n; FI(m){ scan_d(a);scan_d(b);scan_d(c); a--;b--; land[a][b] = min(land[a][b],c); land[b][a] = land[a][b]; } For(i,0,n)For(j,0,n)For(k,0,n) land[j][k] = min(land[j][k],land[j][i] + land[i][k]); For(i,0,all){ For(j,0,n){ dp[i][j] = MOD; } } dp[1][0] = 0; q.push(mp(1,0)); For(i,0,all) { For(j,0,n) if(dp[i][j] != MOD){ For(k,0,n) { if(land[j][k] < 300){ if(!(i & (1<<k))) t = i ^ (1<<k); else t = i; if(dp[i][j] + land[j][k] < dp[t][k]){ dp[t][k] = dp[i][j] + land[j][k]; } } } } } int ans = dp[all-1][0]; For(i,0,n) ans = min(ans,dp[all-1][i] + land[i][0]); printf("%d\n",ans); } } //fclose(stdin); //fclose(stdout); return 0; }