FZU

来源:互联网 发布:电脑静默安装软件 编辑:程序博客网 时间:2024/06/02 00:31

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

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

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


代码:

#pragma comment(linker, "/STACK:1024000000,1024000000")#include<iostream>#include<algorithm>#include<cstdio>#include<cmath>#include<cstring>#include<string>#include<vector>#include<map>#include<set>#include<queue>#include<stack>#include<list>#include<numeric>using namespace std;#define PI acos(-1.0)#define LL long long#define ULL unsigned long long#define INF 0x3f3f3f3f#define mm(a,b) memset(a,b,sizeof(a))#define PP puts("*********************");template<class T> T f_abs(T a){ return a > 0 ? a : -a; }template<class T> T gcd(T a, T b){ return b ? gcd(b, a%b) : a; }template<class T> T lcm(T a,T b){return a/gcd(a,b)*b;}// 0x3f3f3f3f3f3f3f3f// 0x3f3f3f3fint limit;//重复覆盖时使用,行数选择的最大数目struct DLX {const static int ROW = 1003, COL = 1003, SIZE = ROW * COL;int L[SIZE], R[SIZE], U[SIZE], D[SIZE];  //模拟指针int col[SIZE], row[SIZE]; //所在列 所在行int visn, visited[COL]; //用于估价函数int sel[ROW], seln; //选择的行int sz[COL]; //列元素数int total/*节点编号*/, H[ROW];void init(int clen) { //初始化列头指针for(int i = 0; i <= clen; ++i) {L[i] = i - 1; R[i] = i + 1;U[i] = D[i] = i; sz[i] = 0;}for(int i=0;i<ROW;i++) H[i]=-1;for(int i=0;i<COL;i++) visited[i]=0; visn = 0; //用于重复覆盖的A*剪枝L[0] = clen; R[clen] = 0; total = clen + 1;}void link(int r, int c) {//行列都是从下标1开始U[total] = c; D[total] = D[c];U[D[c]] = total; D[c] = total;if(H[r] < 0) H[r] = L[total] = R[total] = total;else {L[total] = H[r]; R[total] = R[H[r]];L[R[H[r]]] = total; R[H[r]] = total;}sz[c]++; col[total] = c; row[total++] = r;}//-------------------- 精确覆盖 -------------------------void remove(const int &c) { //删除c列上所有1元素所在的行L[R[c]] = L[c]; R[L[c]] = R[c];for(int i = D[c]; i != c; i = D[i])for(int j = R[i]; j != i; j = R[j])U[D[j]] = U[j], D[U[j]] = D[j], --sz[col[j]];}void resume(const int &c) { //恢复c列上所有1元素所在的行R[L[c]] = L[R[c]] = c;for(int i = U[c]; i != c; i = U[i])for(int j = L[i]; j != i; j = L[j])++sz[col[U[D[j]] = D[U[j]] = j]];}bool dance(int now) {if(R[0] == 0) {seln = now;return true;}int c=R[0], i, j;for(i = R[0]; i != 0; i = R[i]) //选择元素最少的列cif(sz[c] > sz[i]) c = i;remove(c);for(i = D[c]; i != c; i = D[i]) { //删除与c相连的行ifor(j = R[i]; j != i; j = R[j]) //删除行元素所在的列jremove(col[j]);sel[now] = row[i]; //选择此行 保存行号if(dance(now + 1)) { //对于不同的题 这个地方常常需要改动return true;}for(j = L[i]; j != i; j = L[j])resume(col[j]);}resume(c);return false;}//-------------------- 重复覆盖 -------------------------void _remove(const int &c) {for(int i = D[c]; i != c; i = D[i])L[R[i]] = L[i], R[L[i]] = R[i];}void _resume(const int &c) {for(int i = U[c]; i != c; i = U[i])L[R[i]] = R[L[i]] = i;}int Astar(){ //估价函数int res = 0; ++visn;for(int i = R[0]; i != 0; i = R[i]) {if(visited[i] != visn) {++res; visited[i] = visn;for(int j = D[i]; j != i; j = D[j])for(int k = R[j]; k != j; k = R[k])visited[col[k]] = visn;}} return res;}void _dance(int now) {    if(now + Astar() >= limit){            return;    }if(R[0] == 0){            limit=min(limit,now);            return;}int c=R[0], i, j;for(i = R[0]; i != 0; i = R[i]) //选择元素最少的列cif(sz[c] > sz[i]) c = i;for(i = D[c]; i != c; i = D[i]) {_remove(i);for(j = R[i]; j != i; j = R[j])_remove(j);_dance(now + 1);for(j = L[i]; j != i; j = L[j])_resume(j);_resume(i);}}}dl;int arr[20][20];int main(){    int n,m,n1,m1;    while(~scanf("%d%d",&n,&m)){        int r=1,c=0;        for(int i=1;i<=n;i++)            for(int j=1;j<=m;j++){                scanf("%d",&arr[i][j]);                if(arr[i][j])                    arr[i][j]=++c;            }        dl.init(c);        scanf("%d%d",&n1,&m1);        for(int i=1;i+n1-1<=n;i++)            for(int j=1;j+m1-1<=m;j++){                int flag=0;                for(int k=i;k<=i+n1-1;k++)                    for(int t=j;t<=j+m1-1;t++){                        if(arr[k][t]>0){                            dl.link(r,arr[k][t]);                            flag=1;                        }                    }                if(flag) r++;            }        limit=INF;        dl._dance(0);        printf("%d\n",limit);    }    return 0;}


原创粉丝点击