(状态压缩) Islands and Bridge (P2288)

题意:有N个点,M边条,找到一条哈密尔顿路,求最后的最大值及该值有多少条路径

           第个点的值V[i],路径的值有三个来源

           1、路中所有点的值相加

           2、路中每两个相邻两点的积v[i]*v[j]

           3、路中相隔一点的两点之间存在在路径则相加这三点的积


方法:dp[S][i][j]: S为状态,i为上一个选取点的位置,j为当前选点位置。

                              S中的每个二进制位1表示该点已经路过,否则没有

                      其中存最大值,

            num[S][i][j]: 状态同上,其中存到达该状态最大值的数目。


网址:http://poj.org/problem?id=2288



#include<iostream>
using namespace std;

int n,m;
bool map[13][13];
int dp[1<<13][13][13];
int num[1<<13][13][13];
int v[13];

int main()
{
	freopen("in","r",stdin);
	int i,j,k,t,cur;
	int c;
	cin>>c;
	while (c--)
	{
		cin>>n>>m;
		for (i=0;i<n;i++)
			scanf("%d",v+i);
		memset(map,false,sizeof(map));
		while (m--)
			scanf("%d%d",&i,&j),i--,j--,map[i][j]=map[j][i]=true;
		
		if (n==1)  //点数为1时的特殊处理 
		{
			cout<<v[0]<<' '<<1<<endl;
			continue;
		}
		
		int full=(1<<n)-1; 
		for (i=0;i<=full;i++)   //初始化 
			for (j=0;j<n;j++)
				for (k=0;k<n;k++)
					dp[i][j][k]=num[i][j][k]=-1;
		for (i=0;i<n;i++)   //初始化第一个条件 
			for (j=0;j<n;j++) if (i!=j && map[i][j])
				dp[(1<<i)|(1<<j)][i][j]=v[i]+v[j]+v[i]*v[j],num[(1<<j)|(1<<i)][i][j]=1;
		for (i=0;i<=full;i++)  //对第一个状态逐个计算 
			for (j=0;j<n;j++) if (i&(1<<j))
				for (k=0;k<n;k++)  if (dp[i][j][k]!=-1)
					for (t=0;t<n;t++) if (!((1<<t)&i) && map[k][t])
					{
						cur=dp[i][j][k]+v[t]+v[k]*v[t];
						if (map[j][t])
							cur+=v[j]*v[k]*v[t];
						if (cur>dp[i|(1<<t)][k][t])
							dp[i|(1<<t)][k][t]=cur,num[i|(1<<t)][k][t]=num[i][j][k];
						else if (cur==dp[i|(1<<t)][k][t])
							num[i|(1<<t)][k][t]+=num[i][j][k];
					}
		int big=-1;
		for (i=0;i<n;i++)
			for (j=0;j<n;j++)
				big=max(big,dp[full][i][j]);
		if (big==-1)   //全连通的路径不存在 
		{
			cout<<"0 0"<<endl;
			continue;
		}
		long  long sum=0;
		for (i=0;i<n;i++)  //计算总条件。 
			for (j=0;j<n;j++) if (dp[full][i][j] == big)
				sum+=num[full][i][j];
		cout<<big<<' '<<sum/2<<endl;
	}
	
	
	
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值