题解 P1433 【吃奶酪】

· · 题解

忽然发现其实可以用状压dp的思想来优化dfs...

观察数据,15个奶酪!这数据并不大,根据题意,老鼠走的路径是无后效性的,只要经过的点一致,所在的点也一致,接下来所要走的路径就是等价的

所以可以用一个二进制数来记录走过的点,另一个数记录老鼠所在的点,如果之后搜到的答案比这个点要大,就不继续搜即可,大致思想就是这样

详见代码:

#include <bits/stdc++.h>

using namespace std;

int n;
long double a[30][2],lt[30][30],zt[(1<<15)+15][18];//记录状态,第一维记录走过的点,第二维记录所在的点
long double cc1,cc2,answ;
int bj[30],i,j;

void dfs(int y,int ww,int x,long double ans){//深搜
    if(x==n+1) if(answ==0 || answ>ans) {answ=ans;return;}
    for(int g=1;g<=n;g++)
    {
        if(!bj[g])
        {
            int xb=ww+(1<<(g-1));//xb表示当前已走过的点,有标记数组挡着不用怕二进制数会进位
            if(zt[xb][g]!=0)
            if(zt[xb][g]<=ans+lt[y][g]) continue;//如果生成的路径长度比之前的还要长就不对该点继续dfs
            bj[g]=1;//标记
            zt[xb][g]=ans+lt[y][g];//记录状态
            dfs(g,xb,x+1,zt[xb][g]);//继续往下搜
            bj[g]=0;//回溯
        }
    }
    return;
}

int main(){
    cin>>n;
    a[0][0]=0;a[0][1]=0;
    for(i=1;i<=n;i++)
    {
        scanf("%Lf %Lf",&a[i][0],&a[i][1]);
        for(j=0;j<i;j++)//对两点距离初始化
        {
            cc1=a[i][0]-a[j][0];
            cc2=a[i][1]-a[j][1];
            lt[j][i]=sqrt(cc1*cc1+cc2*cc2);//记录两点距离
            lt[i][j]=lt[j][i];
        }
    }
    dfs(0,0,1,0);
    printf("%.2Lf",answ);
    return 0;
}

有个很奇怪的事,就是优化过的dfs跑第六个点比不优化的还慢,真是玄学