• 【状压DP】【CF8C】 Looking for Order


    传送门

    Description

    给你n个点,每次可以从起点到最多两个点然后回到起点。求经过每个点最少一次的最短欧氏距离和是多少

    Input

    第一行是起点的坐标

    第二行是点的个数(n)

    下面(n)行是需要进过的点的坐标

    Output

    输出最短欧氏距离以及方案。方案是经过每个点的顺序。起点为(0)号点

    Hint

    (For~All:)

    (0~leq~n~leq~24)

    Solution

    看到24就大概能想到是个状压DP

    考虑做法

    (f_S)为走遍(S)中的点的ans。

    转移任意枚举两个或一个点转移

    然而这么做是(O(4^n))的,GG

    考虑事实上对于同一个状态,比如走过前3个点,第一次走1,2,第二次走3和第一次走3,第二次走1,2的答案是一样的。

    于是对于一个集合,只任意选择集合中的一个元素,枚举他是怎么选的,就可以得到最优的答案。

    Code

    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #define rg register
    #define ci const int
    #define cl const long long int
    
    typedef long long int ll;
    
    namespace IO {
    	char buf[300];
    }
    
    template <typename T>
    inline void qr(T &x) {
    	rg char ch=getchar(),lst=' ';
    	while((ch > '9') || (ch < '0')) lst=ch,ch=getchar();
    	while((ch >= '0') && (ch <= '9')) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    	if(lst == '-') x=-x;
    }
    
    template <typename T>
    inline void qw(T x,const char aft,const bool pt) {
    	if(x < 0) {putchar('-');x=-x;}
    	rg int top=0;
    	do {
    		IO::buf[++top]=x%10+'0';
    	} while(x/=10);
    	while(top) putchar(IO::buf[top--]);
    	if(pt) putchar(aft);
    }
    
    template <typename T>
    inline T mmax(const T a,const T b) {return a > b ? a : b;}
    template <typename T>
    inline T mmin(const T a,const T b) {return a < b ? a : b;}
    template <typename T>
    inline T mabs(const T a) {return a < 0 ? -a : a;}
    
    template <typename T>
    inline void mswap(T &a,T &b) {
    	T _temp=a;a=b;b=_temp;
    }
    
    const int maxn = 30;
    const int maxt = 20000000;
    
    struct M {
    	int p,v;
    };
    //M list[maxt];
    
    struct Pos {
    	int x,y;
    };
    Pos MU[maxn];
    
    int sx,sy,n,tcnt;
    int frog[maxt],pre[maxt],list[maxt];
    
    void dfs(ci);
    int cost(ci,ci);
    int dist(ci,ci);
    
    int main() {
    	qr(sx);qr(sy);qr(n);int dn=n-1;
    	MU[n].x=sx;MU[n].y=sy;
    	for(rg int i=0;i<n;++i) {qr(MU[i].x);qr(MU[i].y);}
    	for(rg int i=0;i<dn;++i) {
    		for(rg int j=i+1;j<n;++j) {
    			int p=(1<<i)|(1<<j);
    			int v=cost(i,j);
    			list[p]=v;
    		}
    	}
    	for(rg int i=0;i<n;++i) {
    		int p=1<<i;int v=dist(n,i)<<1;list[p]=v;
    	}
    	int all=(1<<n)-1;
    	memset(frog,0x3f,sizeof frog);frog[0]=0;
    	for(rg int i=1;i<=all;++i) {
    		for(rg int j=0;j<n;++j) if(i&(1<<j)) {
    			for(rg int k=0;k<n;++k) if(i&(1<<k)) {
    				int p=(1<<j)|(1<<k);
    				if(frog[i] > (frog[i^p]+list[p])) frog[i]=frog[i^p]+list[p],pre[i]=p;
    			}
    			break; 
    		}
    	}
    	qw(frog[all],'
    ',true);
    	dfs(all);
    	return 0;
    }
    
    inline int cost(ci a,ci b) {
    	return dist(n,a)+dist(a,b)+dist(b,n);
    }
    
    inline int dist(ci a,ci b) {
    	return (MU[a].x-MU[b].x)*(MU[a].x-MU[b].x)+(MU[a].y-MU[b].y)*(MU[a].y-MU[b].y);
    }
    
    void dfs(ci x) {
    	if(!x) {qw(0,' ',true);return;}
    	dfs(x^pre[x]);
    	for(rg int i=0;i<n;++i) if(pre[x]&(1<<i)) qw(i+1,' ',true);
    	qw(0,' ',true);
    }
    

    Summary

    当多个状态的转移等价的时候,考虑只枚举其中一个状态。

  • 相关阅读:
    java邮箱发送
    mybaties xml 的头部
    eclipse启动报.log错误
    【高性能网站搭建-learn-web-vitals翻译】——Web Vitals
    【高性能网站搭建-learn-web-vitals翻译】——开篇
    git提交代码步骤以及工作中常用的git命令
    苹果手机focus没有效果 键盘跳不出来
    MVC,MVP与MVVM
    媒体查询用法及常见媒体尺寸
    浏览器内核
  • 原文地址:https://www.cnblogs.com/yifusuyi/p/9827762.html
Copyright © 2020-2023  润新知