首页 > 代码库 > FZU 1686 DLX建图重复覆盖

FZU 1686 DLX建图重复覆盖

Problem 1686 神龙的难题

Accept: 394    Submit: 1255
Time Limit: 1000 mSec    Memory Limit : 32768 KB

Problem Description

这是个剑与魔法的世界.英雄和魔物同在,动荡和安定并存.但总的来说,库尔特王国是个安宁的国家,人民安居乐业,魔物也比较少.但是.总有一些魔物不时会进入城市附近,干扰人民的生活.就要有一些人出来守护居民们不被魔物侵害.魔法使艾米莉就是这样的一个人.她骑着她的坐骑,神龙米格拉一起消灭干扰人类生存的魔物,维护王国的安定.艾米莉希望能够在损伤最小的前提下完成任务.每次战斗前,她都用时间停止魔法停住时间,然后米格拉他就可以发出火球烧死敌人.米格拉想知道,他如何以最快的速度消灭敌人,减轻艾米莉的负担.

Input

数据有多组,你要处理到EOF为止.每组数据第一行有两个数,n,m,(1<=n,m<=15)表示这次任务的地区范围.然后接下来有n行,每行m个整数,如为1表示该点有怪物,为0表示该点无怪物.然后接下一行有两个整数,n1,m1 (n1<=n,m1<=m)分别表示米格拉一次能攻击的行,列数(行列不能互换),假设米格拉一单位时间能发出一个火球,所有怪物都可一击必杀.

Output

输出一行,一个整数,表示米格拉消灭所有魔物的最短时间.

Sample Input

4 41 0 0 10 1 1 00 1 1 01 0 0 12 24 4 0 0 0 00 1 1 00 1 1 00 0 0 02 2

Sample Output

41

Source

FOJ月赛-2009年2月- TimeLoop


把每一个怪物编号,然后枚举矩形左上角,扫描矩形内的怪物编号建图,行为矩形的左上角编号,列为怪物编号,模型转化为选取最少的矩形将列上的怪物覆盖,很明显的

dlx重复覆盖。

代码:

/* ***********************************************
Author :_rabbit
Created Time :2014/4/29 16:17:31
File Name :9.cpp
************************************************ */
#pragma comment(linker, "/STACK:102400000,102400000")
#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <sstream>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <string>
#include <time.h>
#include <math.h>
#include <queue>
#include <stack>
#include <set>
#include <map>
using namespace std;
#define INF 0x3f3f3f3f
#define eps 1e-8
#define pi acos(-1.0)
typedef long long ll;
struct DLX{
    const static int maxn=2010;
    #define FF(i,A,s) for(int i = A[s];i != s;i = A[i])
    int L[maxn],R[maxn],U[maxn],D[maxn];
    int size,col[maxn],row[maxn],s[maxn],H[maxn];
    bool vis[2010];
	int ans[maxn],cnt;
    void init(int m){
        for(int i=0;i<=m;i++){
            L[i]=i-1;R[i]=i+1;U[i]=D[i]=i;s[i]=0;
        }
        memset(H,-1,sizeof(H));
        L[0]=m;R[m]=0;size=m+1;
    }
	void link(int r,int c){
         U[size]=c;D[size]=D[c];U[D[c]]=size;D[c]=size;
         if(H[r]<0)H[r]=L[size]=R[size]=size;
         else {
             L[size]=H[r];R[size]=R[H[r]];
             L[R[H[r]]]=size;R[H[r]]=size;
         }
         s[c]++;col[size]=c;row[size]=r;size++;
     }
	void del(int c){//精确覆盖
        L[R[c]]=L[c];R[L[c]]=R[c];  
        FF(i,D,c)FF(j,R,i)U[D[j]]=U[j],D[U[j]]=D[j],--s[col[j]];  
    }  
    void add(int c){  //精确覆盖
        R[L[c]]=L[R[c]]=c;  
        FF(i,U,c)FF(j,L,i)++s[col[U[D[j]]=D[U[j]]=j]];  
    }  
	bool dfs(int k){//精确覆盖
        if(!R[0]){  
            cnt=k;return 1;  
        }  
        int c=R[0];FF(i,R,0)if(s[c]>s[i])c=i;  
        del(c);  
        FF(i,D,c){  
            FF(j,R,i)del(col[j]);  
            ans[k]=row[i];if(dfs(k+1))return true;  
            FF(j,L,i)add(col[j]);  
        }  
        add(c);  
        return 0;
    }  
    void remove(int c){//重复覆盖
        FF(i,D,c)L[R[i]]=L[i],R[L[i]]=R[i];
    }
     void resume(int c){//重复覆盖
         FF(i,U,c)L[R[i]]=R[L[i]]=i;
     }
    int A(){//估价函数
        int res=0;
        memset(vis,0,sizeof(vis));
        FF(i,R,0)if(!vis[i]){
                res++;vis[i]=1;
                FF(j,D,i)FF(k,R,j)vis[col[k]]=1;
            }
        return res;
    }
    void dfs(int now,int &lim){//重复覆盖
        if(R[0]==0)lim=min(lim,now);
        else if(now+A()<lim){
            int temp=INF,c;
            FF(i,R,0)if(temp>s[i])temp=s[i],c=i;
            FF(i,D,c){
                remove(i);FF(j,R,i)remove(j);
                dfs(now+1,lim);
                FF(j,L,i)resume(j);resume(i);
            }
        }
    }
}dlx;
int main()
{
	int n,m,rr,cc,mp[20][20],x,n1,m1;
    while(~scanf("%d%d",&n,&m)){
        cc = 0;rr = 0 ;
        memset(mp,0,sizeof(mp));
        for(int i = 1 ; i <= n ; i ++ )
            for(int j = 1 ; j <= m ; j++ ){
                scanf("%d",&x);
                if(x == 1 )mp[i][j] = ++ cc;
                else mp[i][j] = 0 ;
            }

        dlx.init(cc);
        scanf("%d%d",&n1,&m1);
        for(int i = 1 ; i<= n - n1 + 1 ; i ++ )
            for(int j = 1 ; j <= m - m1 + 1; j ++ )
            {
                rr ++ ;
                for(int i1 = i ; i1 <= i + n1 - 1 ; i1 ++ )
                    for(int j1 = j ; j1 <= j + m1 - 1 ; j1 ++ )
                        if(mp[i1][j1] != 0 )
                          dlx.link(rr,mp[i1][j1]);
            }
        int ans = n * m;
        dlx.dfs(0,ans);
        printf("%d\n",ans);

    }
    return 0;
}