题目链接
问题描述
给你一个图表,你必须从城市开始,ID为零。
输入
第一行是n(1<=n<=21)m(0<=m<=3)
下一个n行显示了图,每一行都有n个整数。
JTH整数表示到城市j的长度,如果这个数字是-1,则表示没有办法。如果i=j,这个数字必须是-1,你可以假设长度不大于10000
下一个m行,每一行都有两个整数a,b(0<=a,b<n)表示路径必须首先访问城市。
输入端带有EOF。输出量
对于每个测试用例,输出Hamilton路径的最小长度。
如果找不到路径,则输出-1。样本输入
3 0 -1 2 4 -1 -1 2 1 3 -1 4 3 -1 2 -1 1 2 -1 2 1 4 3 -1 1 3 2 3 -1 1 3 0 1 2 3
样本输出
4 5
Hint
I think that all of you know that a!=b and b!=0
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<vector>
#include<cmath>
#include<string>
#include<map>
#include<queue>
using namespace std;
typedef long long ll;
#define INF 0x3f3f3f3f
ll dp[3000000][22],mp[22][22],f[22];
int main(){
ll n,m;
while(cin>>n>>m){
for(ll i=0;i<n;i++){
for(ll j=0;j<n;j++){
cin>>mp[i][j];
}
}
//记录每个节点之前必须经历的节点
//的集合,如:1 3 2 3 4 3.f[3]的集合是1,2,4,
memset(f,0,sizeof(f));
//接下来对dp进行初始化,不能memset,超内存,不知原因
//dp[s][i]状态定义为在集合s里面以点i为终点
//的最优路径长度;置初值无穷大
for(ll i=0;i<(1<<n);i++){
for(ll j=0;j<n;j++){
dp[i][j]=INF;
}
}
// memset(dp,INF,sizeof(dp));
dp[1][0]=0;//目前合法的是集合里面只有0,终点也为0
for(ll i=0;i<m;i++){
ll x,y;
cin>>x>>y;
f[y]|=(1<<x);//将x节点加入到y的前驱节点集合中去
}
ll len=(1<<n);
for(ll s=1;s<len;s++){//枚举所有的集合
for(ll i=0;i<n;i++){//枚举所有的终点
if(dp[s][i]==INF)continue;//如果状态合法才拓展
for(ll j=1;j<n;j++){//枚举所有要加入集合的点
if(!(s&(1<<i)))continue;//如果i不在集合里,忽略
if(mp[i][j]==-1)continue;//如果没有i->j的路径,忽略
if(s&(1<<j))continue;//如果j已经在集合s中,忽略
if(f[j]!=(s&f[j]))continue;//如果新加节点的前驱节点集合
//小于当前集合,说明还有前驱点为经历,
//还不能走这个点,返回
dp[(s|(1<<j))][j]=min(dp[(s|(1<<j))][j],dp[s][i]+mp[i][j]);
}
}
}
ll ans=INF;
ll S=(1<<n)-1;
for(ll i=0;i<n;i++){
ans=min(ans,dp[S][i]);
}
if(ans>=INF){
cout<<-1<<endl;
}
else cout<<ans<<endl;
}
return 0;
}