zoukankan      html  css  js  c++  java
  • [bzoj3590]Quare——状压DP

    题目大意:

    给定一个图,求一个边的子集,使得整张图为边双连通并且边的权值和最小。

    思路:

    数据范围这么小,考虑状压DP。
    题目要求子图为边双连通,边双连通可以表示成若干个环套在一起,但是这样并不方便我们表示状态。
    思考一下,不难发现一个边双可以这样组成:一个边双不断地添加一条链并且使这条链首尾都和边双里的任意一个点相连。
    于是转移的大致思路便出来了,枚举一条链并且将这一条链接入目前的集合中,每一次保证最小代价。
    于是我们要预处理任意一条链自己本身连通的最小值
    还有一个点向一个集合中连边的最小值
    由于一条链可能只有一个点,所以还要处理次小值
    然后直接转移就好了。

    #include<bits/stdc++.h>
    
    #define REP(i,a,b) for(int i=a,i##_end_=b;i<=i##_end_;++i)
    #define DREP(i,a,b) for(int i=a,i##_end_=b;i>=i##_end_;--i)
    #define debug(x) cout<<#x<<"="<<x<<endl
    #define pii pair<int,int>
    #define fi first
    #define se second
    #define mk make_pair
    #define pb push_back
    typedef long long ll;
    
    using namespace std;
    
    void File(){
    	freopen("bzoj3590.in","r",stdin);
    	freopen("bzoj3590.out","w",stdout);
    }
    
    template<typename T>void read(T &_){
    	T __=0,mul=1; char ch=getchar();
    	while(!isdigit(ch)){
    		if(ch=='-')mul=-1;
    		ch=getchar();
    	}
    	while(isdigit(ch))__=(__<<1)+(__<<3)+(ch^'0'),ch=getchar();
    	_=__*mul;
    }
    
    const int maxn=13;
    const int maxm=45;
    const int maxw=(1<<13)+10;
    const int inf=0x3f3f3f3f;
    int T,n,m,dp[maxw],all;
    int G[maxn][maxn],line[maxn][maxn][maxw],mx[maxn][maxw][2];
    vector<pii>to[maxn];
    
    void init(){
    	read(n); read(m);
    	all=(1<<n)-1;
    	REP(i,1,m){
    		int u,v,w;
    		read(u),read(v),read(w);
    		G[u][v]=min(G[u][v],w);
    		G[v][u]=min(G[v][u],w);
    		to[u].pb(mk(v,w));
    		to[v].pb(mk(u,w));
    	}
    	REP(i,1,n)line[i][i][1<<(i-1)]=0;
    	REP(S,1,all){
    		if(__builtin_popcount(S)==1)continue;
    		REP(L,1,n)if((1<<(L-1))&S)
    			REP(R,1,n)if(((1<<(R-1))&S) && L!=R){
    				REP(k,1,n)if(((1<<(k-1))&S) && k!=L){
    					int va=G[L][k],vb=line[k][R][S^(1<<(L-1))];
    					if(va==inf || vb==inf)continue;
    					line[L][R][S]=min(line[L][R][S],va+vb);
    				}
    			}
    	}
    	REP(i,1,n)REP(S,1,all)if(!((1<<(i-1))&S)){
    		REP(j,0,to[i].size()-1){
    			int v=to[i][j].fi,val=to[i][j].se;
    			if(!((1<<(v-1))&S))continue;
    			if(val<mx[i][S][0])swap(mx[i][S][0],mx[i][S][1]),mx[i][S][0]=val;
    			else mx[i][S][1]=min(mx[i][S][1],val);
    		}
    	}
    }
    
    void work(){
    	dp[1]=0;
    	REP(S,0,all){
    		if(dp[S]==inf)continue;
    		for(int S0=(all^S);S0;S0=(S0-1)&(all^S)){
    			int va,vb,vc;
    			REP(i,1,n)if((1<<(i-1))&S0){
    				if(__builtin_popcount(S0)==1){
    					va=mx[i][S][0],vb=mx[i][S][1];
    					if(va!=inf && vb!=inf)
    						dp[S^S0]=min(dp[S^S0],dp[S]+va+vb);
    					break;
    				}
    				REP(j,1,n)if(((1<<(j-1))&S0) && i!=j){
    					va=mx[i][S][0],vb=mx[j][S][0],vc=line[i][j][S0];
    					if(va!=inf && vb!=inf && vc!=inf)
    						dp[S^S0]=min(dp[S^S0],dp[S]+va+vb+vc);
    				}
    			}
    		}
    	}
    	if(dp[all]!=inf)printf("%d
    ",dp[all]);
    	else puts("impossible");
    }
    
    int main(){
    	File();
    	read(T);
    	while(T--){
    		memset(line,63,sizeof(line));
    		memset(mx,63,sizeof(mx));
    		memset(G,63,sizeof(G));
    		memset(dp,63,sizeof(dp));
    		init();
    		work();
    		REP(i,0,maxn-1)to[i].clear();
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    vue--todolist的实现
    vue--使用定时器的问题
    vue--动态路由和get传值
    vue--非父子组件之间的传值
    Atitit 图像处理之仿油画效果 Oilpaint油画滤镜 水彩画 漫画滤镜 v2
    Atitit 图像处理 公共模块 矩阵扫描器
    Atitit 文档资料管理同步解决方案
    Atitit 拦截数据库异常的处理最佳实践
    Atitit 数据处理查询 中的异常标准化草案 jpa jdbc hb  oql规范attilax总结
    Atitit oodbms的查询,面向对象的sql查询jpa jpql hql
  • 原文地址:https://www.cnblogs.com/ylsoi/p/9861129.html
Copyright © 2011-2022 走看看