最近做狀壓動規做上癮了.hdu3920.一看就知道這不是個禿論.
方程:dp[s|(1<<i)|(1<<j)]=dp[s]+min(cost(i,j));
注意幾點
1.顯然當確定要消去i點和j點的時候,就應該貪心地先消去里起始點最近的點
2.轉移時可以限制i是按照標號順序可以被消去的第一個點,然後直接只枚舉j.這樣狀態不會減少,轉移複雜度大大減少.
3.這狀態轉移方程的拓撲關係比較混亂,所以可以根據這個轉移方程建立一個有向圖然後廣搜一遍.
source code:
#include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <iostream> using namespace std; #define maxn 21 #define clr(a) memset(a,0,sizeof(a)) #define inf (1000000000) const int maxs=(1<<20); struct point{ double x,y; }; point p[maxn]; point st; double dp[maxs]; int q[maxs+2]; double tmpd; int testcase,ff,rr,n,s; inline double sqr(double a){ return a*a; } inline double dis(point a,point b){ return sqrt(sqr(a.x-b.x)+sqr(a.y-b.y)); } bool compare(const point &a,const point &b){ return dis(st,a)<dis(st,b); } int main(){ freopen("in.txt","r",stdin); scanf("%d",&testcase); for(int ttestcase=1;ttestcase<=testcase;++ttestcase){ printf("Case #%d: ",ttestcase); scanf("%lf%lf",&st.x,&st.y); scanf("%d",&n),n+=n; for(int i=0;i<n;i++) scanf("%lf%lf",&p[i].x,&p[i].y); sort(p,p+n,compare); s=(1<<n); for(int i=1;i<s;i++) dp[i]=inf; dp[0]=0,ff=1,rr=0,q[1]=0; for(int tmp,i,j,tmps;rr<ff;){ tmp=q[++rr]; for(i=0;i<n;i++) if(!(tmp&(1<<i))) break; for(j=i+1;j<n;j++) if(!(tmp&(1<<j))){ tmps=(tmp|(1<<i)|(1<<j)); tmpd=dp[tmp]+dis(st,p[i])+dis(p[i],p[j]); if(dp[tmps]>tmpd){ if(dp[tmps]>=inf) q[++ff]=tmps; dp[tmps]=tmpd; } } } printf("%.2lf\n",dp[s-1]); } fclose(stdin); return 0; }
没有评论:
发表评论