状态压缩DP Hie with the Pie
这是一道最短路+状压的题;
详细注释都在代码里。
题意:输入一个数n,现在有n个地方(标号1到n)要从标号为0的地方出去,经过所有的地方之后回来,求最短的时间
输入(n+1)*(n+1)的矩阵表示每两点之间到达所需要的时间。
d[i][j]表示从i-1到j-1的时间;
dp[i][j]=min(dp[i][j],dp[i^tmp][k]+d[k][j]);
思路:i从小到大列举,从经过一个城市开始,到经过所有城市,慢慢列举;
先前的数为后面的数的基础;
比如:dp[i][j],i表示目前已经经过1 3 4,j为2;
我们这里就可以通过枚举dp[i^tmp][k]+d[k][j],分别以1或者3或者4为i经过的最后
一个点来枚举去最小值;
1 #include<cstdio> 2 #include<string.h> 3 #include<algorithm> 4 using namespace std; 5 const int inf=0x3f3f3f3f; 6 int dp[1<<11][11]; 7 int d[12][12]; 8 int main() 9 { 10 int n; 11 while(scanf("%d",&n)!=EOF){ 12 if(n==0) break; 13 for(int i=0;i<=n;i++) 14 for(int j=0;j<=n;j++){ 15 scanf("%d",&d[i][j]); 16 } 17 18 //最短路代码; 19 for(int k=0;k<=n;k++) 20 for(int i=0;i<=n;i++) 21 for(int j=0;j<=n;j++){ 22 d[i][j]=min(d[i][j],d[i][k]+d[k][j]); 23 } 24 25 //dp[i][j]表示从i的情况下,到j这个点的距离; 26 //其中这个i是用二进制表示的,而j表示的是从1~n; 27 //i的情况的意思:已经经过了的城市; 28 //列举从1到2^n-1的情况 29 for(int i=1;i<(1<<n);i++){ 30 for(int j=1;j<=n;j++){ 31 int tmp=1<<(j-1); 32 //用二进制表示的j,目的是便于下文用& ^之类的符号; 33 if(tmp==i) dp[i][j]=d[0][j]; 34 //如果tem==i,dp[i][j]就表示只经过了j这个点,所以 35 //就是dp[0][j]从0到这个点距离 36 else if(tmp&i){ //如果i中的城市中有j这个城市 37 dp[i][j]=inf; //先定义为正无穷 38 for(int k=1;k<=n;k++){ 39 if(k!=j&&((1<<(k-1))&i)) //如果i的城市中有K这个城市, 40 //才有下文; 41 dp[i][j]=min(dp[i][j],dp[i^tmp][k]+d[k][j]); 42 } 43 } 44 } 45 } 46 int x=(1<<n)-1; 47 int ans=inf; 48 for(int i=1;i<=n;i++) 49 ans=min(ans,dp[x][i]+d[i][0]); 50 //在已经经过所有城市的中枚举从1~n到原点的情况 51 //找出最大值; 52 printf("%d\n",ans); 53 } 54 return 0; 55 }