围栏问题(爆搜)
题目描述
在一片草原上,有n只兔子无忧无虑地生活着。这片草原可以划分成m×m的方阵。每个方格内最多有一只兔子。
一位饲养员负责喂养这些兔子。为了方便,她需要用篱笆建造最多k座围栏,将草原上的兔子全部围起来。
围栏需要满足以下条件:
(1)必须沿着网格线建造;
(2)每座围栏是一个不与自身重叠或相交的封闭回路;
(3)各座围栏之间互相不重叠、不相交;
(4)一座围栏不能被围在另一座围栏里面。
请你帮助饲养员计算一下围栏总长度的最小值。
输入
输入文件名为fence.in
输入第1行为三个整数m,k,n。
接下来n行每行为一对正整数x,y,表示第x行第y列的方格中有一只兔子。
输出
输出文件名为fence.out
输出仅1行,为一个正整数,表示围栏总长度的最小值。
样例输入
【输入输出样例1】
fence.in
6 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; }