Petya and Spiders DLX+重复覆盖 最小支配集(最少多少个点能覆盖所有的点)
2011-10-11 21:47
465 查看
Little Petya loves training spiders. Petya has a board n × m in size. Each cell of the board initially has a spider sitting on it. After one second Petya chooses a certain action for each spider, and all of
them humbly perform its commands. There are 5 possible commands: to stay idle or to move from current cell to some of the four side-neighboring cells (that is, one command for each of the four possible directions). Petya gives the commands so that no spider
leaves the field. It is allowed for spiders to pass through each other when they crawl towards each other in opposite directions. All spiders crawl simultaneously and several spiders may end up in one cell. Petya wants to know the maximum possible number of
spider-free cells after one second.
Input
The first line contains two space-separated integers n and m (1 ≤ n, m ≤ 40, n·m ≤ 40) — the board sizes.
Output
In the first line print the maximum number of cells without spiders.
Sample test(s)
Input
Output
Input
Output
Note
In the first sample the only possible answer is:
s
In the second sample one of the possible solutions is:
s denotes command "stay idle", l, r, d, u denote commands "crawl left", "crawl right", "crawl down", "crawl up", correspondingly.
//
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<algorithm>
#include<iostream>
using namespace std;
#define eps 1e-8
#define N 185
#define V 36000
int n,m;//n行 m列
int L[V],R[V];
int D[V],U[V];
int C[V];
int S
,H
,mark[V],OK
,tans[V];
int ak,size;//ak 最少多少行可以覆盖所有列(可重复)
void Link(int r,int c)
{
S[c]++;C[size]=c;
U[size]=U[c];D[U[c]]=size;
D[size]=c;U[c]=size;
if(H[r]==-1) H[r]=L[size]=R[size]=size;
else
{
L[size]=L[H[r]];R[L[H[r]]]=size;
R[size]=H[r];L[H[r]]=size;
}
mark[size]=r;
size++;
}
void remove(int c)
{
int i;
for(i=D[c];i!=c;i=D[i])
L[R[i]]=L[i],R[L[i]]=R[i];
}
void resume(int c)
{
int i;
for(i=U[c];i!=c;i=U[i])
L[R[i]]=R[L[i]]=i;
}
int h()
{
int i,j,k,count=0;
bool visit
;
memset(visit,0,sizeof(visit));
for(i=R[0];i;i=R[i])
{
if(visit[i]) continue;
count++;
visit[i]=1;
for(j=D[i];j!=i;j=D[j])
{
for(k=R[j];k!=j;k=R[k])
visit[C[k]]=1;
}
}
return count;
}
void Dance(int k)
{
int i,j,c,Min,ans;
ans=h();
if(k+ans>=ak) return;
if(!R[0])
{
if(k<ak)
{
ak=k;
for(int i=0;i<k;i++)
{
tans[i]=mark[OK[i]];
}
}
return;
}
for(Min=N,i=R[0];i;i=R[i])
if(S[i]<Min) Min=S[i],c=i;
for(i=D[c];i!=c;i=D[i])
{
OK[k]=i;
remove(i);
for(j=R[i];j!=i;j=R[j])
remove(j);
Dance(k+1);
for(j=L[i];j!=i;j=L[j])
resume(j);
resume(i);
}
return;
}
int xx[5]={0,0,0,1,-1};
int yy[5]={0,1,-1,0,0};
int mat[400][400];
int main()
{
int tn,tm;
while(scanf("%d%d",&tn,&tm)==2)
{
memset(mat,0,sizeof(mat));
for(int i=1;i<=tn;i++)
{
for(int j=1;j<=tm;j++)
{
for(int k=0;k<5;k++)
{
int x=i+xx[k],y=j+yy[k];
if(x>=1&&x<=tn&&y>=1&&y<=tm)
{
mat[(i-1)*tm+j][(x-1)*tm+y]=1;
}
}
}
}
n=tn*tm,m=tn*tm;
//DLX
for(int i=0;i<=m;i++)
{
S[i]=0;
U[i]=D[i]=i;
L[i+1]=i;R[i]=i+1;
}R[m]=0;
memset(H,-1,sizeof(H));
memset(mark,0,sizeof(mark));
memset(tans,0,sizeof(tans));
size=m+1;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{//cout<<i<<".."<<j<<endl;
if(mat[i][j]) Link(i,j);
}
}
ak=N;
Dance(0);
printf("%d\n",n-ak);
// for(int i=0;i<ak;i++) cout<<tans[i]<<endl;
}
return 0;
}
them humbly perform its commands. There are 5 possible commands: to stay idle or to move from current cell to some of the four side-neighboring cells (that is, one command for each of the four possible directions). Petya gives the commands so that no spider
leaves the field. It is allowed for spiders to pass through each other when they crawl towards each other in opposite directions. All spiders crawl simultaneously and several spiders may end up in one cell. Petya wants to know the maximum possible number of
spider-free cells after one second.
Input
The first line contains two space-separated integers n and m (1 ≤ n, m ≤ 40, n·m ≤ 40) — the board sizes.
Output
In the first line print the maximum number of cells without spiders.
Sample test(s)
Input
1 1
Output
0
Input
2 3
Output
4
Note
In the first sample the only possible answer is:
s
In the second sample one of the possible solutions is:
rdl rul
s denotes command "stay idle", l, r, d, u denote commands "crawl left", "crawl right", "crawl down", "crawl up", correspondingly.
//
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<algorithm>
#include<iostream>
using namespace std;
#define eps 1e-8
#define N 185
#define V 36000
int n,m;//n行 m列
int L[V],R[V];
int D[V],U[V];
int C[V];
int S
,H
,mark[V],OK
,tans[V];
int ak,size;//ak 最少多少行可以覆盖所有列(可重复)
void Link(int r,int c)
{
S[c]++;C[size]=c;
U[size]=U[c];D[U[c]]=size;
D[size]=c;U[c]=size;
if(H[r]==-1) H[r]=L[size]=R[size]=size;
else
{
L[size]=L[H[r]];R[L[H[r]]]=size;
R[size]=H[r];L[H[r]]=size;
}
mark[size]=r;
size++;
}
void remove(int c)
{
int i;
for(i=D[c];i!=c;i=D[i])
L[R[i]]=L[i],R[L[i]]=R[i];
}
void resume(int c)
{
int i;
for(i=U[c];i!=c;i=U[i])
L[R[i]]=R[L[i]]=i;
}
int h()
{
int i,j,k,count=0;
bool visit
;
memset(visit,0,sizeof(visit));
for(i=R[0];i;i=R[i])
{
if(visit[i]) continue;
count++;
visit[i]=1;
for(j=D[i];j!=i;j=D[j])
{
for(k=R[j];k!=j;k=R[k])
visit[C[k]]=1;
}
}
return count;
}
void Dance(int k)
{
int i,j,c,Min,ans;
ans=h();
if(k+ans>=ak) return;
if(!R[0])
{
if(k<ak)
{
ak=k;
for(int i=0;i<k;i++)
{
tans[i]=mark[OK[i]];
}
}
return;
}
for(Min=N,i=R[0];i;i=R[i])
if(S[i]<Min) Min=S[i],c=i;
for(i=D[c];i!=c;i=D[i])
{
OK[k]=i;
remove(i);
for(j=R[i];j!=i;j=R[j])
remove(j);
Dance(k+1);
for(j=L[i];j!=i;j=L[j])
resume(j);
resume(i);
}
return;
}
int xx[5]={0,0,0,1,-1};
int yy[5]={0,1,-1,0,0};
int mat[400][400];
int main()
{
int tn,tm;
while(scanf("%d%d",&tn,&tm)==2)
{
memset(mat,0,sizeof(mat));
for(int i=1;i<=tn;i++)
{
for(int j=1;j<=tm;j++)
{
for(int k=0;k<5;k++)
{
int x=i+xx[k],y=j+yy[k];
if(x>=1&&x<=tn&&y>=1&&y<=tm)
{
mat[(i-1)*tm+j][(x-1)*tm+y]=1;
}
}
}
}
n=tn*tm,m=tn*tm;
//DLX
for(int i=0;i<=m;i++)
{
S[i]=0;
U[i]=D[i]=i;
L[i+1]=i;R[i]=i+1;
}R[m]=0;
memset(H,-1,sizeof(H));
memset(mark,0,sizeof(mark));
memset(tans,0,sizeof(tans));
size=m+1;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{//cout<<i<<".."<<j<<endl;
if(mat[i][j]) Link(i,j);
}
}
ak=N;
Dance(0);
printf("%d\n",n-ak);
// for(int i=0;i<ak;i++) cout<<tans[i]<<endl;
}
return 0;
}
相关文章推荐
- hdu 2295 Radar 重复覆盖 DLX+二分答案 给出一些城市及一些雷达的坐标,要求从这些雷达中选取最多k个能够覆盖所有的城市,问雷达的最小覆盖半径为多少
- hdu 3529 Bomberman - Just Search 重复覆盖+DLX 炸弹人游戏中,问最少需要放多少颗炸弹,才能够将所有的墙壁炸掉,其中,炸弹在同一时间引爆
- hdu 3498 whosyourdaddy 重复覆盖+DLX 每次攻击i和i的所有邻居,最少攻击多少人才能杀死所有敌人
- 【2015-2016 ACM-ICPC Pacific Northwest Regional Contest (Div 1)A】【floyd 最小路径覆盖】最少飞机数满足所有航班要求
- (hdu step 6.3.3)Air Raid(最小路径覆盖:求用最少边把所有的顶点都覆盖)
- hdu 3656 Fire station 重复覆盖 DLX+二分答案 给出一些城市及一些救火站的坐标,要求这些救火站覆盖所有的城市,问从救火站到城市的最长时间至少是多少。
- fzu 1686 神龙的难题 重复覆盖+DLX 用最少的子矩阵覆盖矩阵没所有的1
- HDU 3957 Street Fighter (最小支配集 DLX 重复覆盖+精确覆盖 )
- 果园里有一堆苹果,一共n头(n大于1小于9)熊来分,第一头为小东,它把苹果均分n份后,多出了一个,它扔掉了这一个,拿走了自己的一份苹果,接着第二头熊重复这一过程,即先均分n份,扔掉一个然后拿走一份,以此类推直到最后一头熊都是这样(最后一头熊扔掉后可以拿走0个,也算是n份均分)。问最初这堆苹果最少有多少个。
- 度度熊有一张网格纸,但是纸上有一些点过的点,每个点都在网格点上,若把网格看成一个坐标轴平行于网格线的坐标系的话,每个点可以用一对整数x,y来表示。度度熊必须沿着网格线画一个正方形,使所有点在正方形的内部或者边界。然后把这个正方形剪下来。问剪掉正方形的最小面积是多少。
- 贪心法求树的最小支配集,最小点覆盖,最大独立集
- 【Codeforces Round 330 (Div 2)E】【贪心 暴力】Edo and Magnets 给定矩形最多去除m个,最小面积矩形使得覆盖所有小矩形重心
- POJ2594 Treasure Exploration 最小点覆盖题目[有重复点]
- 树形DP 树的最小支配集,最小点覆盖与最大独立集
- 求能覆盖到所有点的最少集合情况(超时题,须优化)
- 树的最小支配集、最小点覆盖、最大独立集【模板】
- 一条长l的笔直的街道上有n个路灯,若这条街的起点为0,终点为l,第i个路灯坐标为ai,每盏灯可以覆盖到的最远距离为d,为了照明需求,所有灯的灯光必须覆盖整条街,但是为了省电,要是这个d最小,请找到这个最小的d。
- 题目:有1、2、3、4个数字,能组成多少个互不相同且无重复数字的三位数?都是多少? 1.程序分析:可填在百位、十位、个位的数字都是1、2、3、4。组成所有的排列后再去掉不满足条件的排列。
- 关于最大匹配,最小点覆盖,最少路径覆盖和最大独立集的总结
- 面试题精选(84):使序列有序的最少交换次数(minimum swaps) + 删除序列中所有重复的元素