poj 2288 Islands and Bridges_状态压缩dp_哈密尔顿回路问题

题目链接

题目描述:哈密尔顿路问题。n个点,每一个点有权值,设哈密尔顿路为 C1C2...Cn,Ci的权值为Vi,一条哈密尔顿路的值分为三部分计算:
1.每一个点的权值之和
2.对于图中的每一条CiCi+1,加上Vi*Vi+1
3.对于路径中的连续三个点:CiCi+1Ci+2,若在图中,三点构成三角形,则要加上Vi*Vi+1*Vi+2
求一条汉密尔顿路可以获得的最大值,并且还要输出有多少条这样的哈密尔顿路。

这道题的状态感觉不是很难想,因为根据一般的哈密尔顿路问题,首先想到的是设计二维状态,dp[i , s]表示当前在i点,走过的点形成状态集合s。但是这道题在求解值的时候有一个不一样的地方,就是第三部分,如果还是设计成二维的状态,就会很麻烦,因为每加入一个新点,要判断新点、当前点、倒数第二个点是否构成三角形,所以要记录倒数第二个点。很自然地想到扩展状态的维数,增加一维,记录倒数第二个点。

1>  设计状态:
dp[i , j , s]表示当前站在j点,前一个点是i点,形成的状态集合是s,此时的最大值,way[i , j , s]记录当前状态下达到最大值的路径数;
2>  状态转移:
设k点不在集合s中,且存在边
设q为下步到达k点获得的最大值
令r = s + (1< 若i,j,k形成三角形,则q = dp[i][j][s] + v[k] + v[j]*v[k] + v[i]*v[j]*v[k]
否则,q = dp[i][j][s] + v[k] + v[j]*v[k];
若q大于dp[j][k][r];则:
dp[j][k][r] = q
way[j][k][r] = way[i][j][s];
若q等于dp[j][k][r],则:
way[j][k][r] += way[i][j][s];
3>  初始化:
显然,若i点到j点有边,则: 
dp[i][j][(1< way[i][j][(1< 4>  结果的产生:
最后的结果我们要枚举点i和j,找到最大的dp[i][j][(1< 此外,需要注意的是discuss提到的特殊情况,要用__int64,并且注意n等于1时,最大值就是第一个点的权值,路径数为1。


#include 
#include
#include
using namespace std;
const int MAXN =13;
const int MAXS =1<dp[j][k][r]){
						dp[j][k][r]=q;
						way[j][k][r]=way[i][j][p];
					}else if(q==dp[j][k][r]){//相等时,有多个相等价值路径 
						way[j][k][r]+=way[i][j][p];
					}
				}
			} 
		}
	}
}
int main(int argc, char** argv) {
	
	int t,x,y,i,j;
	scanf("%d",&t);
	while(t--){
		memset(map,0,sizeof(map));
		scanf("%d%d",&n,&m);
		for(i=0;iansv){//s-1为经过所有岛 
					ansv=dp[i][j][s-1];
					ansp=way[i][j][s-1];
				}else if(dp[i][j][s-1]==ansv){
					ansp+=way[i][j][s-1];
				}
			}
		printf("%I64d %I64d\n",ansv==-1?0:ansv,ansp/2);
	}
	return 0;
}



你可能感兴趣的:(ACM-ICPC,acm-icpc,动态规划,dp)