【鸽】poj3311 Hie with the Pie[状压DP+Floyd]
题解网上一搜一大坨的,不用复述了吧。
只是觉得网上dp方程没多大问题,但是状态的表示含义模糊。不同于正常哈密顿路径求解,状态表示应当改一下。
首先定义一次移动为从一个点经过若干个点到达另一个点,则$f[S][i]$个人认为应当表示经过若干次移动,每次移动的终点状态记为$1$,由此构成的集合$S$,也就是说,每次移动的中间路过点都不算在内。$i$是最后一次移动的终点。
下面重点解决两个问题:
- 为什么不记路过点,状态表示仍然是对的?
- 不记路过点,走过的一条路,必然可以通过相同的一步一步走的路径把每一步都记成$1$。
- 怎么处理重复走?
- 重复走点的时候状态不会变,终止节点会变,但由于状态设计的定义,导致如果这样可以产生更新,则一定可以通过更少的移动来更新出来。
但是实际上个人理解仍不透彻,所以具体问什么是对的,怎么证明,还尚不清楚。所以人类又要鸽的本质显现。。。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 #define dbg(x) cerr << #x << " = " << x <<endl 7 using namespace std; 8 typedef long long ll; 9 typedef double db; 10 typedef pair<int,int> pii; 11 template<typename T>inline T _min(T A,T B){return A<B?A:B;} 12 template<typename T>inline T _max(T A,T B){return A>B?A:B;} 13 template<typename T>inline char MIN(T&A,T B){return A>B?(A=B,1):0;} 14 template<typename T>inline char MAX(T&A,T B){return A<B?(A=B,1):0;} 15 template<typename T>inline void _swap(T&A,T&B){A^=B^=A^=B;} 16 template<typename T>inline T read(T&x){ 17 x=0;int f=0;char c;while(!isdigit(c=getchar()))if(c=='-')f=1; 18 while(isdigit(c))x=x*10+(c&15),c=getchar();return f?x=-x:x; 19 } 20 const int N=11; 21 int f[1<<11][N],dis[N][N]; 22 int n; 23 24 int main(){//freopen("test.in","r",stdin);//freopen("test.ans","w",stdout); 25 while(read(n),n){ 26 memset(f,0x3f,sizeof f); 27 for(register int i=0;i<=n;++i)for(register int j=0;j<=n;++j)read(dis[i][j]); 28 for(register int k=0;k<=n;++k) 29 for(register int i=0;i<=n;++i) 30 for(register int j=0;j<=n;++j) 31 MIN(dis[i][j],dis[i][k]+dis[k][j]); 32 for(register int i=1;i<=n;++i)f[1<<i][i]=dis[0][i]; 33 for(register int i=1;i<1<<n+1;++i) 34 for(register int j=0;j<=n;++j)if(i&(1<<j)) 35 for(register int k=0;k<=n;++k)if(k^j) 36 MIN(f[i|(1<<k)][k],f[i][j]+dis[j][k]); 37 printf("%d\n",f[(1<<n+1)-1][0]); 38 } 39 return 0; 40 }