• 【洛谷5776】[SNOI2013] Quare(状压DP)


    点此看题面

    • 给定一张(n)个点(m)条边的图,求边权和最小的边双子图。
    • (nle12,mle40)

    边双的拆解

    边双相关的一个结论:一个边双可以拆成一个边双子图以及一条链。

    因此我们设(f_i)表示使得点集(i)成为边双的最小边权和,(g_{x,y,i})表示以(x,y)为两端、由点集(i)中的点构成的链的最小边权和,并设(Mn_{x,i}/Sn_{x,i})表示(x)到点集(i)的最小/次小边权辅助转移。

    记录两点(x,y)间的最小边权为(w_{x,y}),次小边权为(u_{x,y})

    (Mn_{x,i}/Sn_{x,i})的转移显然是非常简单的,就是枚举点集中的一个点,将(w_{x,i})(u_{w,i})与当前最小值和次小值比较。

    (g_{x,y,i})的转移只需考虑枚举(i)以外的一个点(z)扩展,加上(w_{y,z}),将(z)加入点集中并更新端点(y)(z)

    (f_i)的转移就是考虑枚举(i)以外的一个点集(j),在其中枚举两个端点(x,y),列出转移式:

    [f_{icup j}=egin{cases}f_i+g_{x,y,j}+Mn_{x,i}+Mn_{y,i}&x ot=y,\f_i+g_{x,y,j}+Mn_{x,i}+Sn_{y,i}&x=yend{cases} ]

    代码:(O(3^nn^2))

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 12
    #define INF (int)7e6
    #define Gmin(x,y) (x>(y)&&(x=(y)))
    using namespace std;
    int n,m,w[N+5][N+5],u[N+5][N+5],f[1<<N],g[N+1][N+1][1<<N],Mn[N+1][1<<N],Sn[N+1][1<<N];
    int main()
    {
    	RI Tt,i,j,k,l,x,y,z;scanf("%d",&Tt);W(Tt--)
    	{
    		for(scanf("%d%d",&n,&m),i=1;i<=n;++i) for(j=1;j<=n;++j) w[i][j]=u[i][j]=i^j?INF:0;
    		for(i=1;i<=m;++i) scanf("%d%d%d",&x,&y,&z),
    			w[x][y]>z?(u[x][y]=u[y][x]=w[x][y],w[x][y]=w[y][x]=z):u[x][y]=u[y][x]=min(u[x][y],z);//求出两点间最小边权和次小边权
    		for(l=1<<n,i=1;i^l;++i) f[i]=INF;for(i=1;i<=n;++i) for(j=1;j<=n;++j) for(k=1;k^l;++k) g[i][j][k]=INF;//初始全赋成INF
    		for(i=1;i<=n;++i) f[1<<i-1]=g[i][i][1<<i-1]=0;//单点赋成0
    		for(i=1;i<=n;++i) for(j=1;j^l;++j) for(Mn[i][j]=Sn[i][j]=INF,x=1;x<=n;++x)//预处理点到点集的最小边权/次小边权
    			(j>>x-1&1)&&(Mn[i][j]>w[i][x]?(Sn[i][j]=min(Mn[i][j],u[i][x]),Mn[i][j]=w[i][x]):Gmin(Mn[i][j],w[i][x]));//枚举点集中每个点比较
    		for(k=1;k^l;++k) for(i=1;i<=n;++i) for(j=1;j<=n;++j)//预处理g
    			for(x=1;x<=n;++x) !(k>>x-1&1)&&Gmin(g[i][x][k|(1<<x-1)],g[i][j][k]+w[j][x]);//枚举一个新端点扩展
    		for(i=1;i^l;++i) for(j=1;j^l;++j) if(!(i&j)) for(x=1;x<=n;++x) for(y=1;y<=n;++y)//DP求解f
    			(j>>x-1&1)&&(j>>y-1&1)&&Gmin(f[i|j],f[i]+g[x][y][j]+Mn[x][i]+(x^y?Mn:Sn)[y][i]);//根据x,y是否相同简单讨论
    		f[l-1]==INF?puts("impossible"):printf("%d
    ",f[l-1]);
    	}return 0;
    }
    
    败得义无反顾,弱得一无是处
  • 相关阅读:
    你的服务器和网站为什么会被反复入侵
    MAC 查看当前安装的JDK位置
    Jmeter高并发测试
    解密AndroidManifest.xml、AXMLPrinter2.jar源码下载
    Win10家庭版如何启用本地组策略
    SQLFlow使用中的注意事项--设置篇
    Sqlflow 之隐私政策(Privacy plolicy)介绍
    血缘关系分析工具SQLFLOW--实践指南
    Oracle SQL 性能优化利器
    SQLFlow数据流分析工具的job功能介绍
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/Luogu5776.html
Copyright © 2020-2023  润新知