zoukankan      html  css  js  c++  java
  • NOIP2017 宝藏 (状压dp)

    题目等价于给定无向图, 求一棵有根生成树, 假设树的根为$rt$, 对于树上的边$(u,v,w)$, 花费为$dep[v]*w$, 使得总花费最小.

    设$dp[S][d]$为当前集合为$S$, 树的深度为$d$时的最小花费.

    有$dp[S][d]=min{dp[S'][d-1]+cost[S'][S]}$

    $S'$是$S$的子集, $cost$可以预处理, 总的复杂度是$O(n^22^n+n3^n)$

    #include <iostream>
    #include <cstdio>
    #include <string.h>
    #define REP(i,a,n) for(int i=a;i<=n;++i)
    using namespace std;
    
    const int N = 12, INF = 0x3f3f3f3f;
    int n, m, a[N][N];
    int dp[1<<N][N], f[1<<N][N];
    int c[1<<N][1<<N];
    
    int main() {
    	scanf("%d%d", &n, &m);
    	memset(a,INF,sizeof a);
    	REP(i,1,m) {
    		int u,v,w;
    		scanf("%d%d%d",&u,&v,&w);
    		--u,--v;
    		a[u][v]=a[v][u]=min(a[u][v],w);
    	}
    	int mx = (1<<n)-1;
    	memset(f,INF,sizeof f);
    	REP(s,1,mx) REP(i,0,n-1) if (s>>i&1) { 
    		f[s][i] = 0;
    		REP(j,0,n-1) if (s>>j&1^1) f[s][j] = min(f[s][j], a[i][j]);
    	}
    	memset(dp,INF,sizeof dp);
    	REP(i,0,n-1) dp[1<<i][0] = 0;
    	REP(d,1,n-1) REP(i,1,mx) {
    		for (int j=i-1&i; j; --j&=i) if (dp[j][d-1]!=INF) {
    			if (!c[i][j]) {
    				long long sum = 0;
    				REP(k,0,n-1) sum += (i>>k&1)*f[j][k];
    				if (sum>=INF) c[i][j] = INF;
    				else c[i][j] = sum;
    			}
    			if (c[i][j]==INF) continue;
    			dp[i][d] = min(dp[i][d], dp[j][d-1]+c[i][j]*d);
    		}
    	}
    	int ans = INF;
    	REP(i,0,n-1) ans = min(ans, dp[mx][i]);
    	printf("%d
    ", ans);
    }
    
  • 相关阅读:
    avalon如何用年月日的方式输出..
    做一个倒计时的功能,天,时,分 /时,分,秒
    avalon用background-image不起作用,怎么来选取前几个的图片进行渲染
    获取地址栏的参数的两种方法?
    mac屏幕录制
    数据可视化
    vscode 插件
    git 命令 总结
    jest
    react admin
  • 原文地址:https://www.cnblogs.com/uid001/p/11041310.html
Copyright © 2011-2022 走看看