[ L i n k \frak{Link} Link]
给定一个 1 ≤ n ≤ 13 \frak{1\le n\le13} 1≤n≤13点 1 ≤ m ≤ 100 \frak{1\le m\le100} 1≤m≤100边无向图,每个点有权值 1 ≤ v i ≤ 100 \frak{1\le v_i\le 100} 1≤vi≤100,
求权值最大的哈密顿回路(以某个点为起点,经过其他每个点一次的回路)的权值和数量。权值定义如下:
1.记 V 1 \frak{V_1} V1表示 ∑ v i \frak{\sum v_i} ∑vi
2.记 V 2 \frak{V_2} V2表示 ∑ v i v i + 1 \frak{\sum v_iv_{i+1}} ∑vivi+1当 v i \frak{v_i} vi和 v i + 1 \frak{v_{i+1}} vi+1在哈密顿回路中且被边直接相连
3.记 V 3 \frak{V_3} V3表示 ∑ v i v i + 1 v i + 2 \frak{\sum v_iv_{i+1}v_{i+2}} ∑vivi+1vi+2当 v i \frak{v_{i}} vi、 v i + 1 \frak{v_{i+1}} vi+1和 v i + 2 \frak{v_{i+2}} vi+2在哈密顿回路中且构成一个连通分量
那么权值 V = ∑ i = 1 3 V i \frak{V=\sum\limits_{i=1}^3V_i} V=i=1∑3Vi。
看见题目的第一反应: ??????????????????
拆开来考虑每个权值。
在某一点时候的状态由之前的两个点决定。按照访问顺序将这三个点标为
A
,
B
,
C
\frak{A,B,C}
A,B,C。
发现一定会有
V
1
\frak{V_1}
V1和
V
2
\frak{V_2}
V2。而
V
3
\frak{V_3}
V3题目也提示了,只要
A
\frak{A}
A和
C
\frak{C}
C有边直接相连就会产生。
这样一来发现其实转移并不难。这道题也确实就只是一个普通的TSP变形。状压即可。
本题细节很多,要注意。
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<queue>
#include<ctime>
using namespace std;
int n,m;
long long Ans=0,t;
long long BAns;
long long Pt[15]={};
bool lnk[15][15]={};
long long F[8200][15][15]={};
long long C[8200][15][15]={};
int main()
{
scanf("%d",&n);
while(~scanf("%d%d",&n,&m))
{
Ans=-1; BAns=0;
memset(lnk,0,sizeof(lnk));
memset(C,0,sizeof(C));
memset(F,-1,sizeof(F));
for(int i=1;i<=n;++i)
{
scanf("%lld",&Pt[i]);
}
if(n==1){printf("%lld 1\n",Pt[1]);continue;} //***
for(int u,v,i=1;i<=m;++i)
{
scanf("%d%d",&u,&v);
lnk[u][v]=lnk[v][u]=1;
}
for(int a=1;a<=n;++a)
{
for(int b=1;b<=n;++b)
{
if(a==b||lnk[a][b]==0)continue;
F[(1<<a-1)|(1<<b-1)][a][b]=Pt[a]*Pt[b]+Pt[a]+Pt[b];
C[(1<<a-1)|(1<<b-1)][a][b]=1; //*
}
}
for(int i=1;i<(1<<n);++i)
{
for(int a=1;a<=n;++a)
{
if(!(i&(1<<a-1)))continue;
for(int b=1;b<=n;++b)
{
if(!(i&(1<<b-1)))continue;
if(lnk[a][b]==0||a==b)continue;
if(F[i][a][b]==-1)continue;
for(int v,t,c=1;c<=n;++c)
{
if(i&(1<<c-1))continue;
if(lnk[b][c]==0||b==c||a==c)continue;
v=i|(1<<c-1);
t=F[i][a][b]+Pt[b]*Pt[c]+Pt[c]+((lnk[a][c])?(Pt[a]*Pt[b]*Pt[c]):0);
if(t>F[v][b][c])F[v][b][c]=t,C[v][b][c]=C[i][a][b]; //*
else if(t==F[v][b][c])C[v][b][c]+=C[i][a][b]; //*
}
}
}
}
t=(1<<n)-1;
for(int i=1;i<=n;++i)
{
for(int j=1;j<=n;++j)
{
if(i==j)continue;
if(F[t][i][j]>Ans)
{
Ans=F[t][i][j];
BAns=C[t][i][j];
}
else if(F[t][i][j]==Ans)BAns+=C[t][i][j];
}
}
if(Ans<0)printf("0 0\n");
else printf("%lld %lld\n",Ans,BAns>>1);
}
return 0;
}
本文探讨了一种解决特定图论问题的方法,即寻找无向图中权值最大的哈密顿回路及其数量。通过状态压缩动态规划(TSP变形),解决了包含1至13个点及最多100条边的图的问题,详细阐述了算法实现过程。

被折叠的 条评论
为什么被折叠?



