poj2531~剪枝dfs枚举题

来源:互联网 发布:淘宝买岛国片搜什么 编辑:程序博客网 时间:2024/05/22 16:05

题意很简单,就是把一堆点分成两个集合,求集合间的边的总和的最大值

直接暴力其实也能过,不过既然分类在剪枝题里我就使劲想怎么剪枝

1.枚举时只需要枚举前一半的情况就可以了,比如有1、2、3这3个点,你选择了1作为集合A,计算结果,那么后面没有必要再选取(2、3)作为集合A这种情况了,因为两者是一样的

2..所有边的和为sum,

当你选择了一个集合A,A集合中各边的总和为is

, 那么集合间的边的总和肯定小于sum-s;

因为当你选取B集合时,肯定会减去很多的边

如果sum-s都比Max小,那肯定不用再枚举下去了

#include<iostream>#include<string>    using namespace std;int n,map[25][25],Max,tra[25],v[25],sum;void dfs(int f,int count,int is,int os){int i,j,ss,x,y;if(count>n/2) //只需要一半的枚举就够了return ;if(sum-is<=Max) return ; //若剩下集合的边权值已经小于Max了,那后续操作显然没有必要if(os>Max)Max=os;for(i=f;i<n;i++){v[i]=1;tra[count]=i;ss=0;for(j=0;j<count;j++)ss+=map[i][tra[j]];x=0;x-=ss;for(j=0;j<n;j++)if(!v[j])x+=map[i][j];dfs(i+1,count+1,is+ss,os+x);v[i]=0;}}int main(){int i,j,num;cin>>n;memset(v,0,sizeof(v));sum=Max=0;for(i=0;i<n;i++)for(j=0;j<n;j++){scanf("%d",&num);map[i][j]=num;sum+=num;}sum/=2; //计算总的边权值dfs(0,0,0,0);cout<<Max<<endl;return 0;}



0 0