zoukankan      html  css  js  c++  java
  • [luoguP3231] [HNOI2013]消毒(最小点覆盖 + 状压)

    传送门

    考虑贪心,控制某一维为1,另两位最大是最优的,也就是一次选一个厚度为1的面

    那么对于每个点,可以有3种面是可以选到它的

    然后gg

    考虑二维的状态,一个平面,有些点,一次选一行或一列最优

    那么每一个点i,j可以被行i和列j选中,将i->j连接一条边,每一条边就代表一个点

    选取最少的点覆盖所有边就是最少点覆盖=最大匹配

    因为a*b*c<=5000所以最小的那一维一定<=17,可以枚举这一维哪些面被一次清除,

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #define N 5001
    
    using namespace std;
    
    int T, a, b, c, n, ans, cnt;
    int now[N][N], head[N], to[N * N], nex[N * N], belong[N];
    bool vis[N];
    
    struct node
    {
    	int x, y, z;
    	node(int x = 0, int y = 0, int z = 0) : x(x), y(y), z(z) {}
    }p[N];
    
    inline int read()
    {
    	int x = 0, f = 1;
    	char ch = getchar();
    	for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = -1;
    	for(; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + ch - '0';
    	return x * f;
    }
    
    inline void clear()
    {
    	int i;
    	ans = cnt = 0;
    	for(i = 1; i <= b; i++) head[i] = -1;
    	for(i = 1; i <= c; i++) belong[i] = 0;
    }
    
    inline void add(int x, int y)
    {
    	to[cnt] = y;
    	nex[cnt] = head[x];
    	head[x] = cnt++;
    }
    
    inline bool dfs(int u)
    {
    	int i, v;
    	for(i = head[u]; ~i; i = nex[i])
    	{
    		v = to[i];
    		if(!vis[v])
    		{
    			vis[v] = 1;
    			if(!belong[v] || dfs(belong[v]))
    			{
    				belong[v] = u;
    				return 1;
    			}
    		}
    	}
    	return 0;
    }
    
    inline int solve()
    {
    	int i, j, k, ret = 1e9;
    	for(k = 0; k < (1 << a); k++)
    	{
    		clear();
    		for(i = k; i; i >>= 1)
    			if(i & 1) ans++;
    		for(i = 1; i <= n; i++)
    			if(!(k & (1 << p[i].x - 1))) now[p[i].y][p[i].z] = 1;
    		for(i = 1; i <= b; i++)
    			for(j = 1; j <= c; j++)
    				if(now[i][j]) add(i, j);
    		for(i = 1; i <= b; i++)
    		{
    			for(j = 1; j <= c; j++) vis[j] = 0;
    			ans += dfs(i);
    		}
    		ret = min(ret, ans);
    		for(i = 1; i <= n; i++)
    			if(!(k & (1 << p[i].x - 1))) now[p[i].y][p[i].z] = 0;
    	}
    	return ret;
    }
    
    int main()
    {
    	int i, j, k, x;
    	T = read();
    	while(T--)
    	{
    		n = 0;
    		a = read();
    		b = read();
    		c = read();
    		for(i = 1; i <= a; i++)
    			for(j = 1; j <= b; j++)
    				for(k = 1; k <= c; k++)
    				{
    					x = read();
    					if(x) p[++n] = node(i, j, k);
    				}
    		if(c < a && c < b)
    		{
    			swap(a, c);
    			for(i = 1; i <= n; i++) swap(p[i].x, p[i].z);
    		}
    		else if(b < c && b < a)
    		{
    			swap(a, b);
    			for(i = 1; i <= n; i++) swap(p[i].x, p[i].y);
    		}
    		printf("%d
    ", solve());
    	}
    	return 0;
    }
    

      

    剩余的面压缩到一起,连边跑匈牙利

  • 相关阅读:
    脚本——1-100的和
    脚本——删除文件为0大小的文件
    脚本——ping网址
    脚本——大于5k的文件有
    脚本——九九乘法表
    第十天:小数与随机数
    第九天:单元测试
    第八天:错误异常处理
    第七天(1):包与模块管理
    第七天(2):面向对象编程
  • 原文地址:https://www.cnblogs.com/zhenghaotian/p/8260740.html
Copyright © 2011-2022 走看看