#include<bits/stdc++.h>//三进制状压dp再做广搜
using namespace std;
const int INF=1e9;
const int maxn=1e5;
int n;
int dp[maxn][13];
int dis[13][13];
int c[11]={1,3,9,27,81,243,729,2187,6561,19683,59049};
int OK[maxn][13];
int NUM[maxn][13];
int a[40][maxn];
int ok(int st,int num)
{
for(int i=0;i<num;i++,st=st/3) if(!(st%3)) return 0;
return 1;
}
void init()
{
for(int i=0;i<c[10];i++) //预处理走遍j个结点的成功状态
for(int j=1;j<=10;j++)
OK[i][j]=ok(i,j);
memset(NUM,0,sizeof(NUM));
for(int i=0;i<c[10];i++) //预处理每个状态三进制表示下各个位的值
{
int num=1,tmp=i,s=0;
while(tmp)
{
NUM[i][num++]=tmp%3;
s=s+tmp%3;
tmp=tmp/3;
}
NUM[i][0]=s;
}
}
int solve()
{
memset(dp,-1,sizeof(dp));
for(int i=1;i<=2*n;i++) //稍做优化
{
int num=1;
for(int j=0;j<c[n];j++) if(NUM[j][0]==i) a[i][num++]=j;
a[i][0]=num;
}
for(int i=1;i<=2*n-1;i++) //走2n-1步结束
for(int j1=1;j1<a[i][0];j1++) //对应合法步数的状态
{
int j=a[i][j1];
for(int k=1;k<=n;k++)
if(NUM[j][k]>=1) //找到已走点 // bug..找了好久(==1)不对
for(int p=1;p<=n;p++)
if(NUM[j][p]<2&&p!=k&&dis[k][p]!=INF) //找到可走点
{
int st=j+c[p-1];
if(i==1) dp[st][p]=dis[k][p];//初始化
else if(dp[j][k]!=-1) //暴力时有些点p不能到
{
if(dp[st][p]==-1) dp[st][p]=dp[j][k]+dis[k][p];//初始化
else dp[st][p]=min(dp[st][p],dp[j][k]+dis[k][p]);
//1001/0101->1101都至dp[st][p];关键点 决定dp,st+一维
}
}
}
int ans=INF;
for(int i=0;i<c[n];i++)
if(OK[i][n])
for(int j=1;j<=n;j++)
if(dp[i][j]!=-1) ans=min(ans,dp[i][j]);
return ans;
}
int main()
{
// freopen("C:/Users/hzy/Desktop/11.txt","r",stdin);
init();
int m;
while(scanf("%d%d",&n,&m)!=EOF)
{
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(i==j) dis[i][j]=0;
else dis[i][j]=INF;
for(int i=0;i<m;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
if(dis[u][v]==INF) dis[u][v]=dis[v][u]=w; //去重边
else dis[u][v]=dis[v][u]=min(dis[u][v],w);
}
int ans=INF;
ans=solve();
if(ans==INF) cout<<-1<<endl;
else cout<<ans<<endl;
}
return 0;
}
状压dp,三进制,tsp
最新推荐文章于 2024-07-29 15:08:31 发布