• 「THUSCH 2017」巧克力(斯坦纳树dp+随机化+中位数二分)


    https://loj.ac/problem/2977

    暴力:状态记录当前选了哪些颜色的点,用斯坦纳树去转移,应该能过个40分。

    对于第2问,考虑先二分答案mid,把<=mid的数权值设为-1,>mid的取值设为1,相当于在联通块点数最少的同时,权值和最小。
    若最小权值和<=0,则说明真正的答案(>=mid),调整二分区间即可。

    对于这种恰好选k个不同的颜色,且k很小的问题,不难想到随机化。
    先给每个颜色随机一个新的(in [1,k])的颜色,把问题转化为把k种颜色全部选到,那么状态就是(2^k)的了。

    一次错误的概率是(1-{k! over k^k}),做(T=150)次,大概有千分之三的错误率。

    Code:

    #include<bits/stdc++.h>
    #define fo(i, x, y) for(int i = x, _b = y; i <= _b; i ++)
    #define ff(i, x, y) for(int i = x, _b = y; i <  _b; i ++)
    #define fd(i, x, y) for(int i = x, _b = y; i >= _b; i --)
    #define ll long long
    #define pp printf
    #define hh pp("
    ")
    using namespace std;
    
    const int N = 235;
    
    int T;
    int n, m, k;
    int c[N][N], a[N][N], v[N][N];
    
    void Init() {
    	scanf("%d %d %d", &n, &m, &k);
    	fo(i, 1, n) fo(j, 1, m) scanf("%d", &c[i][j]);
    	fo(i, 1, n) fo(j, 1, m) scanf("%d", &a[i][j]);
    }
    
    int b[N * N];
    
    int rand(int x, int y) {
    	return ((ll) RAND_MAX * rand() + rand()) % (y - x + 1) + x;
    }
    
    void srand_b()  {
    	int c = n * m / k;
    	fo(i, 1, k * c)	b[i] = (i - 1) / c;
    	fo(i, k * c + 1, n * m) b[i] = rand(0, k - 1);
    	random_shuffle(b + 1, b + n * m + 1);
    }
    
    const int inf = 1e9;
    
    int a2[6];
    
    #define pii pair<int, int>
    #define fs first
    #define se second
    
    pii operator + (pii a, pii b) {
    	return pii(a.fs + b.fs, a.se + b.se);
    }
    
    pii f[32][N][N];
    
    struct P {
    	int x, y;
    	pii v;
    };
    
    bool operator < (P a, P b) { 
    	return a.v > b.v;
    }
    
    priority_queue<P> q;
    
    int us[N][N];
    
    int mov[4][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
    
    pii dp() {
    	ff(s, 0, a2[k]) fo(i, 1, n) fo(j, 1, m)
    		f[s][i][j] = pii(inf, 0);
    	fo(i, 1, n) fo(j, 1, m) if(c[i][j] != -1) {
    		f[0][i][j] = pii(1, v[i][j]);
    		f[a2[b[c[i][j]]]][i][j] = pii(1, v[i][j]);
    	}
    	ff(s, 0, a2[k]) {
    		fo(i, 1, n) fo(j, 1, m) if(c[i][j] != -1) {
    			for(int p = s - 1; p > 0; p = (p - 1) & s) {
    				pii z = f[p][i][j] + f[s ^ p][i][j];
    				z.fs --; z.se -= v[i][j];
    				if(z < f[s][i][j]) f[s][i][j] = z;
    			}
    			q.push((P) {i, j, f[s][i][j]});
    			
    		}
    		fo(i, 1, n) fo(j, 1, m) us[i][j] = 0;
    		while(q.size()) {
    			P b = q.top(); q.pop();
    			if(us[b.x][b.y]) continue;
    			us[b.x][b.y] = 1;
    			fo(k, 0, 3) {
    				int l = b.x + mov[k][0], r = b.y + mov[k][1];
    				if(l && r && l <= n && r <= m && c[l][r] != -1) {
    					pii z = b.v;
    					z.fs ++; z.se += v[l][r];
    					if(z < f[s][l][r]) {
    						f[s][l][r] = z;
    						q.push((P) {l, r, f[s][l][r]});
    					}
    				}
    			}
    		}
    	}
    	pii ans = pii(inf, inf);
    	fo(i, 1, n) fo(j, 1, m)
    		ans = min(ans, f[a2[k] - 1][i][j]);
    	return ans;
    }
    
    int W;
    
    int ans1, ans2;
    
    int p[N], p0;
    
    void work() {
    	for(int l = 1, r = p0; l <= r; ) {
    		int mi = l + r >> 1;
    		fo(i, 1, n) fo(j, 1, m) {
    			v[i][j] = a[i][j] <= p[mi] ? -1 : 1;
    		}
    		pii z = dp();
    		if(z.se > 0) {
    			l = mi + 1;
    		} else {
    			if(z.fs < ans1) ans1 = z.fs, ans2 = p[mi]; else
    				if(z.fs == ans1 && p[mi] < ans2) ans2 = p[mi];
    			r = mi - 1;
    		}
    	}
    }
    
    int main() {
    	srand(time(0) + clock());
    	a2[0] = 1; fo(i, 1, 5) a2[i] = a2[i - 1] * 2;
    	for(scanf("%d", &T); T; T --) {
    		Init();
    		W = 233 * 150 / (n * m);
    		
    		p0 = 0;
    		fo(i, 1, n)	fo(j, 1, m) if(c[i][j] != -1)
    			p[++ p0] = a[i][j];
    		sort(p + 1, p + p0 + 1);
    		p0 = unique(p + 1, p + p0 + 1) - (p + 1);
    		
    		ans1 = ans2 = 1e9;
    		fo(ii, 1, W) {
    			srand_b();
    			work();
    		}
    		if(ans1 == 1e9) pp("-1 -1
    "); else {
    			pp("%d %d
    ", ans1, ans2);
    		}
    	}
    }
    
  • 相关阅读:
    DAY 06 PYTHON入门
    DAY 05 PYTHON入门
    DAY 04 PYTHON入门
    DAY 03 PYTHON入门
    DAY 02 PYTHON入门
    DAY 01 PYTHON入门
    RTC时钟和BKP的配置stm32
    Altium Designer画原理图时要紧凑
    串口的数据长度校验
    Centos7下创建文件夹 移动文件/文件夹 删除文件/文件夹 解压/文件夹打包压缩 命令整理
  • 原文地址:https://www.cnblogs.com/coldchair/p/12639031.html
Copyright © 2020-2023  润新知