zoukankan      html  css  js  c++  java
  • P3231 [HNOI2013]消毒

    洛谷传送门

    Solution

    先考虑二维

    对于一个点 ((x,y)) ,要么是在第 (x) 列被消毒,要么是在第 (y) 列被消毒,考虑二分图匹配,左边是列,右边是行,求最小点覆盖即可。

    回到三维

    显然三分图匹配是不可的,所以要看看别的东西。

    题目中给了 (abcleq 5000) ,也就是 (min{a,b,c}leq sqrt[3] {5000}approx 17) ,所以可以枚举最小的一维,判断是将一层全部消掉还是留下,然后再将剩下的拍成一个二维平面(或者说,将枚举的那一位坐标去掉),按上面二维方法求解即可。

    Code

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    using namespace std;
    struct lsqy{
    	int next,to;
    }q[5010];
    int a,b,c,ys[5101];
    int dir[4][5101],tot; 
    int match[5001],vis[5100],head[5101],cnt;
    int ans=2147483644;
    void add(int x,int y)
    {
    	q[++cnt].next=head[x];
    	head[x]=cnt;
    	q[cnt].to=y;
    }
    bool dfs(int u)
    {
    	for(int i=head[u];i;i=q[i].next)
    	{
    		int v=q[i].to;
    		if(!vis[v])
    		{
    			vis[v]=1;
    			if(dfs(match[v])||!match[v])
    			{
    				match[v]=u;
    				return 1;
    			}
    		}
    	}
    	return 0;
    }
    void work(int s)
    {
    	for(int i=1;i<=b;++i)
    	  head[i]=0;
    	for(int j=1;j<=c;++j)
    	  match[j]=0;
    	cnt=0;
    	int con=0;
    	//memset(ys,0,sizeof(ys));
        for(int i=1;i<=a;++i)
    	  if((1<<(i-1))&s) ys[i]=0,con++;
    	    else ys[i]=1;
        for(int i=1;i<=tot;++i)
          if(ys[dir[1][i]])
            add(dir[2][i],dir[3][i]);
        for(int i=1;i<=b;++i)
        {
          for(int j=1;j<=c;++j)
            vis[j]=0;
          //memset(vis,0,sizeof(vis));
    	  if(dfs(i)) con++;   
    	}
    	ans=min(ans,con); 
    } 
    int main()
    {
    	int T_T,minn;
    	scanf("%d",&T_T);
    	while(T_T--)
    	{
    		tot=0;
    		minn=ans=2147483644;
    		scanf("%d%d%d",&a,&b,&c);
    		minn=min(a,min(b,c));
    		for(int i=1;i<=a;++i)
    		  for(int j=1;j<=b;++j)
    		    for(int k=1;k<=c;++k)
    		      {
    		      	int x;
    		      	scanf("%d",&x);
    		      	if(!x) continue;
    		      	tot++;
    				dir[1][tot]=i;
    		      	dir[2][tot]=j;
    		      	dir[3][tot]=k;
    			  }
    		  if(minn=b) swap(b,a),swap(dir[1],dir[2]);
    		    else if(minn=c)  swap(c,a),swap(dir[1],dir[3]);
    		for(int i=0;i<=(1<<a)-1;++i)
    		  work(i);
    		printf("%d
    ",ans);
    	}
    	
     } 
    

    感谢bored的精彩代码

  • 相关阅读:
    FTP-实例(Md5验证)
    Socket-实例
    函数对象、函数嵌套、名称空间与作用域、装饰器
    Docker——手动创建镜像
    Docker——桥接网络配置
    Docker——网络和存储(数据卷)
    Docker-PS命令解析
    面试题44:扑克牌的顺子
    面试题42:翻转单词顺序VS左旋转字符串
    面试题41:和为s的两个数字VS和为s的连续正数序列
  • 原文地址:https://www.cnblogs.com/jasony/p/13932181.html
Copyright © 2011-2022 走看看