题目链接:Click here~~
题意:
n 个点的竞赛图,找出它的哈密顿路(n <= 100)。
解题思路:
首先,竞赛图是指每两个点之间都有一条边的有向图(即边数为 n*(n-1)/2 )。
然后,对于竞赛图,一定存在哈密顿路。转载一个证明:
求竞赛图中的哈密顿路的算法:
首先,由数学归纳法可证竞赛图在n>=2时必存在哈密顿路;
(1)n=2时显然;
(2)假设n=k时,结论成立,哈密顿路为V1,V2,...,Vi,...,Vk;
现添加第k+1个结点,若存在弧<Vi,Vk+1>和弧<Vk+1,Vi+1>,则可得哈密顿回路V1,V2,...,Vi,Vk+1,Vi+1,...,Vk;
若不存在上述的vi,考虑到Vk+1与v1~vk的连通状况,则只有下面 3 种原哈密顿路的情况:
1.所有的Vi(1<i<k)与Vk+1的弧的方向都是<Vi,Vk+1>,那么可得哈密顿回路V1,V2,...,Vi,...,Vk,Vk+1;
2.所有的Vi(1<i<k)与Vk+1的弧的方向都是<Vk+1,Vi>,那么可得哈密顿回路Vk+1,V1,V2,...,Vi,...,Vk;
3.存在一个中间结点m,使得所有的Vi(1<=i<=m)与Vk+1的弧方向为<Vk+1,Vi>,所有的Vj(m<j<=k)与Vk+1的弧的方向为<Vj,Vk+1>,这时依然可以构造哈密顿路 V1,V2,...,Vi,...,Vk,Vk+1;
对于证明,可能一下子想不到为什么能分为这三种情况。可以从 V1 与 Vk+1 及 Vk 与 Vk+1 的四种情况入手。代码很好写,复杂度O(n^2)。
#include <vector>
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
const int N = 1e2 + 5;
bool reach[N][N];
void Hamitton(int n)
{
vector<int> ans;
ans.push_back(1);
for(int i=2;i<=n;i++)
{
bool cont = false;
for(int j=0;j<(int)ans.size()-1;j++)
if(reach[ ans[j] ][i] && reach[i][ ans[j+1] ])
{
ans.insert(ans.begin()+j+1,i);
cont = true;
break;
}
if(cont)
continue;
if(reach[ ans.back() ][i])
ans.push_back(i);
else
ans.insert(ans.begin(),i);
}
for(int i=0;i<n;i++)
printf("%d%c",ans[i],i==n-1?'\n':' ');
}
int main()
{
int T,n;
scanf("%d",&T);
while(T--)
{
memset(reach,false,sizeof(reach));
scanf("%d",&n);
if(n == 1)
puts("1");
else
{
for(int i=0;i<n*(n-1)/2;i++)
{
int u,v;
scanf("%d%d",&u,&v);
reach[u][v] = true;
}
Hamitton(n);
}
}
return 0;
}