思路讲解
状压dp最好都用0-based
这道题就是三进制状态压缩的板子题
之所以使用三进制,是因为2进制只能表示这个东西选没选,如这个经典的吃奶酪。
三进制可以表示这个城市来过一次or两次
AC代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
| #include <iostream> #include <cstring> #include <algorithm> #include <deque> #include <queue> #include <vector> #include <set> #include <map> #include <cmath> #include <bitset> #include <iterator> #include <random> #include <iomanip> #include <cctype> #include <array>
using namespace std; typedef long long ll; const ll N=static_cast<ll>(2e5)+10; ll n,m; ll road[15][15]; ll dp[60000][12]; ll three[12]; ll digit[60000][12]; const ll INF=99999999;
void init(){ three[0]=1; for(int i=1;i<=10;++i) three[i]=three[i-1]*3; for(int i=0;i<three[10];++i){ int temp=i; for(int j=0;j<10;++j){ digit[i][j]=temp%3; temp/=3; } } }
void init2(){ memset(road, 0x3f, sizeof(road)); memset(dp, 0x3f, sizeof(dp)); for(int i=1;i<=n;++i) road[i][i]=0; for(int i=0; i<n; i++) dp[three[i]][i]=0; }
int main() { ios::sync_with_stdio(false); cin.tie(0);cout.tie(0); init(); while(cin>>n>>m){ init2(); for(int i=1;i<=m;++i){ ll a,b,c; cin>>a>>b>>c; road[a][b]=min(c,road[a][b]); road[b][a]=min(c,road[b][a]); } ll ans=INF; for(int i=1;i<three[n];++i){ bool flag=true; for(int j=0;j<n;++j){ if(!digit[i][j]){ continue; } for(int k=0;k<n;++k){ if(!digit[i][k]){ flag=false; continue; } dp[i][j]=min(dp[i-three[j]][k]+road[k+1][j+1],dp[i][j]); } if(flag) ans=min(ans,dp[i][j]); } }
cout<<(ans==INF ? -1:ans)<<endl; } return 0; }
|
心路历程(WA,TLE,MLE……)
前面调了半天,以为是我的写法有问题,但其实是因为
dp[i][j]=min(dp[i-three[j]][k]+road[k+1][j+1],dp[i][j]);
写成了road[k-1][j-1]
路程匹配错误导致了这个问题
C语言也是的,这个index都超范围了也不给个提示,6。