• ZOJ 3209 Treasure Map【DancingLink】


    ZOJ 3209 Treasure Map
    http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=3372
    大意:已知有一张n*m的图,p个矩形,问至少需要多少个矩形能够完全覆盖整幅图,
          要求不能出现重叠
    分析:
      转化为精确铺盖问题,即将图拉成一条长度为n*m的链,在该图中找到每个矩形
      对应的覆盖点,用DancingLink计算最少需要点数即可。。

    #include<stdio.h>
    #include<string.h>
    const int MAX_COLOUMN = 30*30+2;//最多出现列数
    const int MAX_ROW = 500+2;//最多出现的行数
    
    int cnt[MAX_COLOUMN];//cnt[i]统计第i列1的个数
    int most,coloumn;
    //跳舞链中的节点
    struct Point
    {
       int up,down,left,right;//上,下,左,右
       int coloumn;//该点所在的列标
    
    }node[MAX_ROW*MAX_COLOUMN+MAX_COLOUMN];
    
    //初始化跳舞链信息为空
    void init(int m)
    {
     int i;
     for(i=0;i<=m;i++)
     {
      node[i].down=i;
      node[i].up = i;
      node[i].coloumn=i;
      node[i].left=i-1;
      node[i].right=i+1;
      cnt[i]=0;
     }
     node[0].left = m;
     node[m].right = 0;
    }
    
    void remove(int c)//删除c列上所有1元素所在的行
    {
     node[node[c].right].left=node[c].left;
     node[node[c].left].right=node[c].right;
     int t,tt;
     for(t=node[c].down;t!=c;t=node[t].down)//从上到下从左到右删除该列上的每一非零元素所在行信息
     {
      for(tt = node[t].right;tt!=t;tt=node[tt].right)//删除非零元素所在行
      {
                cnt[node[tt].coloumn]--;
       node[node[tt].down].up = node[tt].up;
       node[node[tt].up].down = node[tt].down;
      }
     }
    }
    
    void resume(int c)//还原c列上所有1元素所在的行
    {
     int t,tt;
     for(t=node[c].up;t!=c;t=node[t].up)//从下往上从左到右还原该c列中1所在的行信息
     {
      for(tt=node[t].left;tt!=t;tt=node[tt].left)
      {
       cnt[node[tt].coloumn]++;
       node[node[tt].up].down=tt;
       node[node[tt].down].up=tt;
      }
     }
    
     node[node[c].right].left=c;
     node[node[c].left].right=c;
    }
    
    void dfs(int k)//k为已经选中的行的数目
    {
     int i,j;
     if(k>=most)return;
     if(node[coloumn].right == coloumn)//当前跳舞链已为空
     {
      if(k<most)
       most = k;
      return;
     }
    
     int t = coloumn+1;
     int c;
     //选取当前矩阵中1最少的列
     for(i=node[coloumn].right;i!=coloumn;i=node[i].right)
     {
      if(cnt[i]<t)
      {
       c=i;t=cnt[i];
       if(t==1)break;
      }
     }
        
     remove(c);//删除列c中所有1所在的行
    
     //删除时从左到右从上到下,还原时从下到上,从右到左
     for(i = node[c].down;i!=c;i=node[i].down)
     {
      for(j=node[i].right;j!=i;j=node[j].right)
      {
       remove(node[j].coloumn);
      }
      dfs(k+1);
     
      for(j=node[j].left;j!=i;j=node[j].left)
      {
       resume(node[j].coloumn);
      }
    
      
     }
    
     resume(c);
    
    }
    bool graph[MAX_ROW][MAX_COLOUMN];
    int wide;//地图的宽度
    inline void addrow(int r,int x1,int y1,int x2,int y2)
    {
       int i,j;
       for(i=x1;i<x2;i++)
        for(j=y1;j<y2;j++)
        {
         graph[r][j*wide+i]=true;
        }
    }
    
    char str[MAX_ROW];
    int main()
    {
     int N,M,i,j;
         int T;
      while(scanf("%d",&T)!=EOF)
      while(T--)
      {
       //printf("%s",str);
        int nn,mm,pp;
        scanf("%d%d%d",&nn,&mm,&pp);
        wide = nn;
        N=pp;
        M=mm*nn;
        coloumn = M;
       int cur=coloumn+1;//当前节点编号
       init(coloumn);
       memset(graph,0,sizeof(graph));
       for(i=0;i<pp;i++)//将图信息放入graph中
       {
        int x1,y1,x2,y2;
        scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
        addrow(i,x1,y1,x2,y2);//添加该行状态
       }
    
    
       for(i=0;i<N;i++)//在跳舞链中插入图中非空位置的点
       {
        int start = cur;//记录第i列的开始点编号
        int pre = cur;//记录该列中当前1的左边第一个1编号
        for(j=0;j<M;j++)
        {
        // scanf("%d",&n);
         if(graph[i][j])//跳舞链中仅插入非0元素
         {
          int pos = j;
          node[cur].up = node[pos].up;
          node[node[pos].up].down = cur;
          node[cur].down = pos;
          node[pos].up = cur;
          cnt[pos]++;//该列1的个数+1
          node[cur].coloumn = pos;
          node[cur].left = pre;
          node[pre].right = cur;
          node[cur].right = start;
          node[start].left=cur;
          pre=cur++;
         }
        }
       }
    
      
       most = N+1;//记录最少需要选中的行数
       dfs(0);
          if(most==N+1)
                 most=-1;   
        printf("%d\n",most);
      }
     
     return 0;
    }
    
  • 相关阅读:
    深度学习之TensorFlow(一)——基本使用
    64位win10+cuda8.0+vs2013+cuDNN V5下Caffe的编译安装教程并配置matlab2014a 接口
    Win10+vs2012+cuda8.0的安装与配置
    图像处理与matlab实例之图像平滑(一)
    Windows下pycharm使用theano的方法
    Python中的支持向量机SVM的使用(有实例)
    混淆矩阵在Matlab中PRtools模式识别工具箱的应用
    模式识别与机器学习—bagging与boosting
    微服务架构下分布式事务解决方案——阿里GTS
    谈谈分布式事务
  • 原文地址:https://www.cnblogs.com/AndreMouche/p/1966148.html
Copyright © 2020-2023  润新知