Travelling
Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 6735 Accepted Submission(s): 2189
2 1 1 2 100 3 2 1 2 40 2 3 50 3 3 1 2 3 1 3 4 2 3 10
100 90 7
思路:明显是状压dp,但是之前我只会二进制的所以楞是没想出来,上网看了题解才知道弄成三进制的就好了,和一般的题目一样第一维表示状态(即每个地点走过几次),第二维表示最后停留的地点,然后就是普通的状压dp。。关键是如何化成三进制,化成三进制的部分挺难说明的,看代码吧。
#include<iostream>
#include<cmath>
#include<queue>
#include<cstdio>
#include<queue>
#include<algorithm>
#include<cstring>
#include<string>
#define maxn 100005
#define inf 0x3f3f3f3f
typedef long long LL;
using namespace std;
int digit[60000][11],dp[60000][11],dis[11][11];//digit[i][j]表示i在三进制下的第j位数是多少
int main(){
int n,m;
int three[11]={1};//three求出3的n次方
for(int i=1;i<=10;i++){
three[i]=three[i-1]*3;
}
for(int i=1;i<three[10];i++){
int temp=i;
for(int j=1;j<11;j++){
digit[i][j]=temp%3;
temp/=3;
if(!temp)
break;
}
}
while(~scanf("%d%d",&n,&m)){
memset(dis,-1,sizeof(dis));
memset(dp,-1,sizeof(dp));
for(int i=0;i<m;i++){
int u,v,value;
scanf("%d%d%d",&u,&v,&value);
if(dis[u][v]==-1){
dis[u][v]=dis[v][u]=value;
}
else{
dis[u][v]=dis[v][u]=min(dis[u][v],value);
}
}
for(int i=1;i<=n;i++){
dp[three[i-1]][i]=0;
}
int ans=inf;
for(int i=1;i<three[n];i++){
bool jud=true;
for(int j=1;j<=n;j++){
if(digit[i][j]){
if(dp[i][j]!=-1){
for(int k=1;k<=n;k++){
if(j==k||dis[j][k]==-1)
continue;
if(digit[i][k]<2){
if(dp[i+three[k-1]][k]==-1)
dp[i+three[k-1]][k]=dp[i][j]+dis[j][k];
else
dp[i+three[k-1]][k]=min(dp[i+three[k-1]][k],dp[i][j]+dis[j][k]);
}
}
}
}
else
jud=false;
}
if(jud){
for(int j=1;j<=n;j++){
if(dp[i][j]==-1)
continue;
ans=min(dp[i][j],ans);
}
}
}
if(ans==inf)
printf("-1\n");
else
printf("%d\n",ans);
}
}//g++ -o a.exe a.cpp
2万+



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



