POJ-2288:Islands and Bridges (小岛和桥)

一、问题描述

Given a map of islands and bridges that connect these islands, a Hamilton path, as we all know, is a path along the

bridges such that it visits each island exactly once. On our map, there is also a positive integer value associated with each island. We call a Hamilton path the best triangular Hamilton path if it maximizes the value described below.

Suppose there are n islands. The value of a Hamilton path C1C2…Cn is calculated as the sum of three parts. Let Vi be the value for the island Ci. As the first part, we sum over all the Vi values for each island in the path. For the second part, for each edge CiCi+1 in the path, we add the product ViVi+1. And for the third part, whenever three consecutive islands CiCi+1Ci+2 in the path forms a triangle in the map, i.e. there is a bridge between Ci and Ci+2, we add the product ViVi+1*Vi+2.

Most likely but not necessarily, the best triangular Hamilton path you are going to find contains many triangles. It is quite possible that there might be more than one best triangular Hamilton paths; your second task is to find the number of such paths.

大概意思:

给定一些岛屿和一些连接岛屿的桥梁,大家都知道汉密尔顿路是访问每个岛屿一次的路线,在我们这个地图中,每个岛屿有个正整数的权值,表示这个岛屿的观赏价值。假设一共有N个岛屿,用Vi表示岛屿Ci的价值,汉密尔顿路C1C2…Cn的价值是以下三部分的总和:

(1)所有岛屿的价值之和;

(2)对于路径中相邻的两个岛屿CiCi+1,把两个岛屿的价值之积加到总价值中;

(3)路径中连续三个岛屿CiCi+1Ci+2,如果Ci与Ci+2有桥直接相连,则把这三个岛屿价值之积加到总价值中。

要求计算汉密尔顿路最大的价值以及方案数。

二、问题分析

设f[s][i][j]表示当前走过点的状态为s(1表示走过,0表示没走过),上一个走到的是点i ,上上个走到的是点j 之后时最大的总价值是多少,于是我们就可以先预处理出经过两个点的状态,然后枚举每一个状态暴力DP转移就行了

至于统计方案数也很简单,设一个g[s][i][j]表示在f[s][i][j]情况下的方案数,转移时只要判断一下有没有大于原来的f,如果大于则g就赋值成转移过来的那个状态的g,如果等于就加上转移过来那个状态的g就行了

之后注意当只有一个岛的时候是可以走完的,需要特别判断一下

三、问题解决

#include<cstdio>
#include<string>
#include<cstring>
#define max(a,b) (((a)>(b))?(a):(b))
#define min(a,b) (((a)<(b))?(a):(b))
#define R register int
#define N 15
#define ll long long
using namespace std;

int q,n,m,ans1,a[N],f[1<<(N-1)][N][N];
ll g[1<<(N-1)][N][N],ans2;
bool b[N][N]; 
inline void read(int &x)
{
	x=0;int f=1;char ch=getchar();
	while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
	while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();x*=f;
}

int main()
{
	read(q);
	while (q--)
	{
		read(n);read(m);
		for (R i=1;i<=n;++i)
			read(a[i]);
		if (n==1) {printf("%d 1\n",a[1]);continue;}
		memset(b,0,sizeof(b));
		for (R i=1;i<=m;++i)
		{
			int x,y;read(x);read(y);
			b[x][y]=b[y][x]=1;
		}
		memset(f,0,sizeof(f));memset(g,0,sizeof(0));
		for (R i=1;i<=n;++i)
			for (R j=1;j<=n;++j)
				if (i!=j && b[i][j]) f[(1<<i-1)|(1<<j-1)][i][j]=a[i]*a[j]+a[i]+a[j],g[(1<<i-1)|(1<<j-1)][i][j]=1;
		int tot=(1<<n)-1;
		for (R s=0;s<=tot;++s)
			for (R i=1;i<=n;++i)
				if ((s&(1<<i-1)))
					for (R j=1;j<=n;++j)
						if (j!=i && s&(1<<j-1) && b[i][j])
							for (R k=1;k<=n;++k)
								if (k!=i && k!=j && s&(1<<k-1) && b[k][j])
								{
									int now=s-(1<<i-1);
									if (f[now][j][k])
									{
										int num=f[now][j][k]+a[i]*a[j]+a[i];
										if (b[i][k]) num+=a[i]*a[j]*a[k];
										if (num>f[s][i][j]) f[s][i][j]=num,g[s][i][j]=g[now][j][k];
										else if (num==f[s][i][j]) g[s][i][j]+=g[now][j][k];
									}
								}
		ans1=ans2=0;
		for (R i=1;i<=n;++i)
			for (R j=1;j<=n;++j)
				if (i!=j)
				{
					if (f[tot][i][j]>ans1) ans1=f[tot][i][j],ans2=g[tot][i][j];
					else if (f[tot][i][j]==ans1) ans2+=g[tot][i][j];
				}
		printf("%d %lld\n",ans1,ans1>0?ans2>>1:0);
	} 
	return 0;
}

四、生词

triangular adj 三角形的

五、参考文章

  1. POJ 2288 Islands and Bridges(状压DP)题解
  2. poj 2288 Islands and Bridges(状压dp)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值