luogu P1433

Posted saudi

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了luogu P1433相关的知识,希望对你有一定的参考价值。

传送门

题目描述

房间里放着 (n) 块奶酪。一只小老鼠要把它们都吃掉,问至少要跑多少距离?老鼠一开始在 ((0,0)) 点处。

输入格式

第一行一个正整数 (n)

接下来每行 (2) 个实数,表示第i块奶酪的坐标。

两点之间的距离公式为 (sqrt{(x_1-x_2)^2+(y_1-y_2)^2})

输出格式

一个数,表示要跑的最少距离,保留 (2) 位小数。

说明/提示

(1 leq n leq 15)

题解

第一眼:暴力dfs一下不就行了吗?为啥是普及+/提高啊?
然后写了10多分钟,写完了

#include <iostream>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>
#include <string>
#include <bitset>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <algorithm>
#include <sstream>
#include <stack>
#include <iomanip>
#include <assert.h>
using namespace std;
#define pb push_back
#define mp make_pair
typedef pair<int,int> pii;
typedef long long ll;
typedef double ld;
typedef vector<int> vi;
#define fi first
#define se second
#define fe first
#define FO(x) {freopen(#x".in","r",stdin);freopen(#x".out","w",stdout);}
#define Edg int M=0,fst[SZ],vb[SZ],nxt[SZ];void ad_de(int a,int b){++M;nxt[M]=fst[a];fst[a]=M;vb[M]=b;}void adde(int a,int b){ad_de(a,b);ad_de(b,a);}
#define Edgc int M=0,fst[SZ],vb[SZ],nxt[SZ],vc[SZ];void ad_de(int a,int b,int c){++M;nxt[M]=fst[a];fst[a]=M;vb[M]=b;vc[M]=c;}void adde(int a,int b,int c){ad_de(a,b,c);ad_de(b,a,c);}
#define es(x,e) (int e=fst[x];e;e=nxt[e])
#define esb(x,e,b) (int e=fst[x],b=vb[e];e;e=nxt[e],b=vb[e])
typedef pair<ld,ld> pdd;
int n;
pdd a[20];
ld ans=114514114514.000;
bool u[20];
ld dis(pdd x,pdd y)
{return sqrt((x.fi-y.fi)*(x.fi-y.fi)+(x.se-y.se)*(x.se-y.se));}
void dfs(int lst,int x,ld sum)
{
    if(x==n)
    {
        ans=min(ans,sum);
        return;
    }
    if(sum>ans) return;
    for(int i=1;i<=n;++i) if(!u[i])
    {
        u[i]=1;
        dfs(i,x+1,sum+dis(a[lst],a[i]));
        u[i]=0;
    }
}
int main()
{
    cin>>n;
    for(int i=1;i<=n;++i) cin>>a[i].fi>>a[i].se;
    dfs(0,0,0.0);
    cout.setf(ios::fixed);
    cout.precision(2);
    cout<<ans<<"
";    
}

交上去后
技术图片

然后卡了一年常数,还是没过
然后我突然发现,这不是个状压dp吗?

然后设计了下状态:dp[s][i]表示当前状态为s(二进制下第(i-1)位代表第(i)个数有没有选),上一个选的数是(i)的最小值。注:二进制的最低位是第0位
然后转移方程就立马出来了~
[ dp[s][i] = min_{1 leq j leq n}{dp[s quad xor quad (1<<(i-1))][j]+dis(i,j)} ]
也就是说(dp[s][i])可以从任何一个之前没选过(i),并且只选(i)就变成(s)的状态转移过来
喜闻乐见的代码

#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
typedef double ld;
typedef pair<ld,ld> pdd;
pdd a[20];
int n;
ld dp[1<<15][20],ans=9999999999999999.000;
ld dis(int x,int y)
{return sqrt((a[x].fi-a[y].fi)*(a[x].fi-a[y].fi)+(a[x].se-a[y].se)*(a[x].se-a[y].se));} //编号为i,j两点间的距离
int main()
{
    memset(dp,127,sizeof(dp)); 
    cin>>n;
    for(int i=1;i<=n;++i) cin>>a[i].fi>>a[i].se;
    for(int i=1;i<=n;++i) dp[1<<(i-1)][i]=dis(i,0); //初始化,从(0,0)点开始走到某一个点
    for(int s=1;s<1<<n;++s)
    {
        for(int i=1;i<=n;++i) if(s&(1<<(i-1))) //只有s当中有i时才转移
        {
            for(int j=1;j<=n;++j) dp[s][i]=min(dp[s][i],dp[s^(1<<(i-1))][j]+dis(i,j)); //转移方程
        }
    }
    for(int i=1;i<=n;++i) ans=min(ans,dp[(1<<n)-1][i]); //统计一下答案
    cout.setf(ios::fixed);
    cout.precision(2);
    cout<<ans<<"
";
}

跑的飞快
技术图片

以上是关于luogu P1433的主要内容,如果未能解决你的问题,请参考以下文章

luogu P1433 吃奶酪

luogu P1433

洛古——P1433 吃奶酪

状压dp小练习(LuoGu)

题解 P1433 吃奶酪

题解 P1433 吃奶酪