围栏问题(爆搜)

题目描述

在一片草原上,有n只兔子无忧无虑地生活着。这片草原可以划分成m×m的方阵。每个方格内最多有一只兔子。

一位饲养员负责喂养这些兔子。为了方便,她需要用篱笆建造最多k座围栏,将草原上的兔子全部围起来。

围栏需要满足以下条件:

(1)必须沿着网格线建造;

(2)每座围栏是一个不与自身重叠或相交的封闭回路;

(3)各座围栏之间互相不重叠、不相交;

(4)一座围栏不能被围在另一座围栏里面。

请你帮助饲养员计算一下围栏总长度的最小值。

输入

输入文件名为fence.in

输入第1行为三个整数mkn

接下来n行每行为一对正整数xy,表示第x行第y列的方格中有一只兔子。

输出

输出文件名为fence.out

输出仅1行,为一个正整数,表示围栏总长度的最小值。

样例输入

【输入输出样例1】
fence.in 
1 4 
1 3 
4 2 
4 4
 6 4
 fence.out
 18

样例输出

【输入输出样例2】
fence.in 
6 2 4 
1 3 
4 2
4 4 
6 4 
fence.out 
16 

提示

【输入输出样例解释1】



如图是一种满足题意的建造方法。



【输入输出样例解释2】



如图是一种满足题意的建造方法。




【数据范围】


对于10%的数据,k=1;


对于10%~30%的数据,k=2;


对于30%~60%的数据,n≤10;


对于100%的数据,1≤k≤n≤16,m≤1,000。



solution:

看到“1<=k<=n<=16”,这个数据非常小,所以可以直接搜索,加上最优性,就可以ac了。

#include<cstdio> 
#include<iostream> 
#include<cmath> 
#include<algorithm> 
#include<cstdlib> 
#include<cstring> 
using namespace std; 
int m,k,n,x[100],y[100],a[100],b[100],c[100],d[100],ans;
void dfs(int t,int num,int sum){
	if(sum>ans)
		return;
	if(t>n){
		ans=sum;
		return;
	}
	if(num<k){
		a[num+1]=x[t];
		b[num+1]=y[t];
		c[num+1]=x[t];
		d[num+1]=y[t];
		dfs(t+1,num+1,sum+4);
		a[num+1]=b[num+1]=c[num+1]=d[num+1]=0;
	}
	int aa,bb,cc,dd;
	for(int i=1;i<=num;i++){
		aa=a[i];
		bb=b[i];
		cc=c[i];
		dd=d[i];
		a[i]=min(a[i],x[t]);
		b[i]=min(b[i],y[t]);
		c[i]=max(c[i],x[t]);
		d[i]=max(d[i],y[t]);
		dfs(t+1,num,sum-2*(cc-aa+1+dd-bb+1)+2*(c[i]-a[i]+1+d[i]-b[i]+1));
		a[i]=aa;
		b[i]=bb;
		c[i]=cc;
		d[i]=dd;
	}
}
int main(){ 
    scanf("%d%d%d",&m,&k,&n); 
    for(int i=1;i<=n;i++) 
        scanf("%d%d",&x[i],&y[i]); 
    ans=1000000000;
    dfs(1,0,0);
    printf("%d\n",ans);
    return 0; 
} 



转载于:https://www.cnblogs.com/RetardedZY/p/7469886.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值