zoukankan      html  css  js  c++  java
  • bzoj1402 Ticket to Ride 斯坦纳树 + 状压dp

    给定(n)个点,(m)条边的带权无向图

    选出一些边,使得(4)对点之间可达,询问权值最小为多少

    (n leqslant 30, m leqslant 1000)


    首先看数据范围,(4)对点,也就是(8)个点,很小

    上斯坦纳树(局部最小生成树)

    然而好像题目并不是斯坦纳树,可能是一些树拼到一起

    那么就再做一个状压(dp)即可

    复杂度(O(3^8 * n + 2^8 * nm + 2^{12} * n))


    #include <map>
    #include <queue>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    using namespace std;
    
    const int sid = 55;
    const int eid = (1 << 9) - 1;
    inline void cmin(int &a, int b) { if(a > b) a = b; }
    
    int n, m, nc;
    int U[sid], V[sid], cl[sid], ip[sid];
    int f[sid][eid], E[sid][sid];
    string s[55], sa, sb;
    map <string, int> id;
    
    int inq[sid];
    queue <int> q;
    void spfa(int S) {
    	memset(inq, 0, sizeof(inq));
    	for(int i = 1; i <= n; i ++) q.push(i);
    	while(!q.empty()) {
    		int id = q.front(); q.pop(); inq[id] = 0;
    		for(int j = 1; j <= n; j ++)
    			if(f[j][S] > f[id][S] + E[id][j]) {
    				f[j][S] = f[id][S] + E[id][j];
    				if(!inq[j]) q.push(j), inq[j] = 1;
    			}
    	}
    }
    
    void wish1() {
    	memset(f, 56, sizeof(f));
    	for(int i = 1; i <= n; i ++)
    		if(cl[i]) {
    			nc ++;
    			ip[i] = nc;
    			f[i][(1 << nc - 1)] = 0;
    		}
    		
    	for(int S = 0; S <= (1 << nc) - 1; S ++) {
    		for(int i = 1; i <= n; i ++)
    			for(int T = S; T; T = (T - 1) & S)
    				cmin(f[i][S], f[i][T] + f[i][S ^ T]);
    		spfa(S);
    	}
    }
    
    int g[eid];
    void wish2() {
    	memset(g, 56, sizeof(g)); g[0] = 0;
    	for(int s = 0; s <= (1 << 4) - 1; s ++)
    	for(int i = 1; i <= n; i ++)
    	for(int S = 0; S <= (1 << nc) - 1; S ++) {
    		int T = 0;
    		for(int k = 1; k <= 4; k ++)
    			if((S & (1 << ip[U[k]] - 1)) && (S & (1 << ip[V[k]] - 1)))
    				T |= (1 << k - 1);
    		cmin(g[s | T], g[s] + f[i][S]);
    	}
    	printf("%d
    ", g[(1 << 4) - 1]);
    }
    
    int main() {
    	freopen("bzoj1402.in", "r", stdin);
    	freopen("bzoj1402.out", "w", stdout);
    	cin >> n >> m;
    	for(int i = 1; i <= n; i ++) {
    		cin >> s[i];
    		id[s[i]] = i;
    	}
    	memset(E, 56, sizeof(E));
    	for(int i = 1; i <= m; i ++) {
    		int u, v, w;
    		cin >> sa >> sb >> w;
    		u = id[sa]; v = id[sb];
    		cmin(E[u][v], w); E[v][u] = E[u][v];
    	}
    	for(int i = 1; i <= 4; i ++) {
    		int u, v;
    		cin >> sa >> sb;
    		u = id[sa]; v = id[sb];
    		U[i] = u; V[i] = v;
    		cl[u] = cl[v] = 1;
    	}
    	wish1(); wish2();
    	return 0;
    }
    
  • 相关阅读:
    C语言中typedef可以出现在struct定义之前
    C语言编程规划——怎样用C语言设计一个程序
    如何去掉页眉页脚上的横线 如何去掉页眉上的横线 如何去掉页脚上的横线
    在Visual Studio 2005中使用WinPcap编写程序的配置方法
    使用WinPcap编程(1)——获取网络设备信息
    如何思考多维数组
    Visual Studio 2005编写C程序出错:error C2143,)前缺少*
    在Linux下运行peersim1.0.5
    Login failed for user 'IIS APPPOOL\DefaultAppPool'
    win2008 r2 安装sqlserver2005 sp3报错
  • 原文地址:https://www.cnblogs.com/reverymoon/p/10076783.html
Copyright © 2011-2022 走看看