POJ2531-Network Saboteur-暴力枚举+记忆化/dfs/随机化乱搞

。。。题目没什么好说的。

把n个点 分配到两个集合,   求sum= A集合每个点到B集合所有点的边的权重和

n=20; 

。暴力的算法就直接枚举每种情况

1、暴力枚举复杂度 2^19 * 20*20  复杂度略大..TLE...加个剪枝去掉一半 也要跑1S   .POJ的数据太水。。

枚举的时候可以利用位运算,重复利用一下之前的结果(复杂度2^n * n ),不用每次枚举把所有的值都求和,大概也能跑200ms


2、dfs,没剪枝也能过2^20* n ...400ms,比枚举快多了(枚举干了很多不必要的加法...) 

剪枝:  把求A-B之间最大外部和转为求AB各自最小内部和...

有些大牛剪完枝直接就16MS了。。。

3、随机化乱搞... 每次随机改变1个节点从A到B 或B到A,for 一遍更新sum值,重复10W次,基本都ac了,当然和数据规模有关系啦....   参考别人的代码大概也是100+MS



关于bitmask。。之前一直是 遍历i的每一位...今天看别人的写法会 更快一些... 

暴力枚举+记忆化:

#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
#include <map>  
#include <stack>
#include <iostream>
using namespace std;   
double eps=0.000001; 
int tm[25][25];
int set[25];
int vis[5+(1<<20)];
int f[5+(1<<20)];
int main()
{
	int st,i,j,k;
	int n;
	cin>>n;
	for (i=1;i<=n;i++)
	{
		for (j=1;j<=n;j++)
		{
			scanf("%d",&tm[i][j]);
		}
	}
	int maxx=0;
	int all=1<<(n)-1;
	
	for (k=1;k<all;k++)
	{
		if (vis[k]) continue;
		vis[k]=1;
		vis[k^all]=1; //剪枝1/2,使得复杂度变成 2^(n-1)
		
		//-k&k是求k的lowbit位(最低位边的1)
		//k-lowbit(k)得到【A集合】的上一个状态
		//那么当前状态的sum值f[k]=f[last]+当前新增的点x到B集合的sum-之前A集合到x的sum
		int lowbit=-k&k;
		int last=k-lowbit;
		f[k]=f[last]; 

		int x=0;    //j便是新增的点 
		while(lowbit)
		{x++;lowbit>>=1;}

		for (j=1;j<=n;j++)
		{
			if ((1<<(j-1))&last)//表示j已经在A集合
				f[k]-=tm[x][j];
			else		//j在B集合
				f[k]+=tm[x][j];
		} 
		f[k^all]=f[k]; 
		if (f[k]>maxx)	maxx=f[k];
	}
	printf("%d\n",maxx);
	
	return 0;
}


暴力枚举代码:  1S

#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
#include <map>  
#include <stack>
#include <iostream>
using namespace std;  
__int64 inf=15;
double eps=0.000001; 
int tm[25][25];
int set[25];
int vis[1<<20+5];
int main()
{
	int st,i,j,k;
	 int n;
	 cin>>n;
	 for (i=1;i<=n;i++)
	 {
		 for (j=1;j<=n;j++)
		 {
		 scanf("%d",&tm[i][j]);
		 }
	 }
	 __int64 maxx=0;
	 int all=1<<(n)-1;
	 
	 for (k=0;k<=all;k++)
	 {
		 if (vis[k]) continue;
		 vis[k]=1;
		 vis[k^all]=1; //剪枝1/2,使得复杂度变成 2^(n-1)
		set[1]++;
		for (i=1;i<=n;i++)
		{
			if (set[i]==2)
			{
				set[i]=0;
				set[i+1]++;
			}
			else break;
		}
		__int64 sum=0;
		for(i=1;i<=n;i++)
		{
			 
			if (!set[i]) continue; 
					for (j=1;j<=n;j++)
					{
					if (!set[j])
						sum+=tm[i][j];
					} 
		}
		if (sum>maxx)maxx=sum;
	 }
	 printf("%I64d\n",maxx);
 
return 0;
}



dfs:200ms

#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
#include <map>  
#include <stack>
#include <iostream>
using namespace std;  
double eps=0.000001; 
int tmd[25][25];
int set[25];
int maxx;
	 int n; 
int dfs(int x,int sum)
{ 
	if (x>n)
	{ 
		if (sum>maxx)
			maxx=sum;
		return 0;
	}
	int tmdp=0,i;set[x]=0;
	for (i=1;i<=x;i++)
	{
		if (!set[i]) continue;
		tmdp+=tmd[i][x];//不把x选入A,sum+=[x到A集的和]
	}
	dfs(x+1,sum+tmdp);
	tmdp=0;
	set[x]=1;
	for (i=1;i<=x;i++)
	{
		if (set[i])continue;
		tmdp+=tmd[i][x];  //把x选入A,sum+=[x到B集的和]
	}  
	
 	dfs(x+1,sum+tmdp);

  
} 

int main()
{
	int st,i,j,k;
	int t; 
	   cin>>n; 
	 for (i=1;i<=n;i++)
	 {
		 for (j=1;j<=n;j++)
		 {
		 scanf("%d",&tmd[i][j]); 
		 }
	 }
	 maxx=0;
	 dfs(1,0);

	 printf("%d\n",maxx); 
return 0;
}


随机化乱搞:http://blog.csdn.net/sssogs/article/details/8221244

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值