标签:
首先,对图进行一次Floyd(g[][]是图)
1.dfs:(u是当前在的节点,d是已经走的路程)
void dfs(int u,int d){ if(d>=ans)return; bool flag=false; for(int i=1;i<=n;i++){ if(vis[i]==false&&i!=u){ flag=true; vis[i]=true; dfs(i,d+g[u][i]); vis[i]=false; } } if(flag==false){ d+=g[u][0]; if(ans>d)ans=d; } }
起初我认为n<=15是dfs完全可以解决的,但是忽略了一个问题:每对城市之间都可以互相到达,边特别多,结果TLE ^_^;
正解是压缩状态的dp:
dp[u][s]表示状态:走到u这个点并且前面已经走完了集合s中的点 的最短距离
s是二进制压缩状态 1到过 0没有
ps:u这个点本身也包括在集合s中
s0是把s中u去掉后的集合 s0 = s & ((1<<n)-1 - (1<<(u-1)) ) //@_@a...
dp[u][s]=min{ dp[i][s0]+g[i][u] }
i是集合s0中包含的点,注意是 +g[i][u],因为是先走到i,再从i到u(题目中说城市a到城市b的时间和城市b到城市a的时间不一定相同)
代码如下:
#include<iostream> #include <bitset> #include<cstring> using namespace std; int n; int g[16][16]; int dp[16][1<<15]; bool vis[16][1<<15]; void Floyd(){ for(int k=0;k<=n;k++){ for(int i=0;i<=n;i++){ for(int j=0;j<=n;j++){ if(i==k||j==k||i==j)continue; g[i][j]=min(g[i][j], g[i][k]+g[k][j]); } } } } /*void dfs(int u,int d){ if(d>=ans)return; bool flag=false; for(int i=1;i<=n;i++){ if(vis[i]==false&&i!=u){ flag=true; vis[i]=true; dfs(i,d+g[u][i]); vis[i]=false; } } if(flag==false){ d+=g[u][0]; if(ans>d)ans=d; } }*/ int dfs(int u,int s){ if(vis[u][s])return dp[u][s]; vis[u][s]=true; int s0= s & ((1<<n)-1 - (1<<(u-1)) ); //cout<<u<<" "<<bitset<sizeof(int)*8>(s)<<" "<<bitset<sizeof(int)*8>(s0)<<endl; int cnt=0; int& ans=dp[u][s]; for(int i=1;i<=15;i++){ if(s0&(1<<(i-1))){ cnt++; int x=dfs(i, s0)+g[i][u]; ans=min(ans,x); } } if(cnt==0){ ans=g[0][u]; } return ans; } int main(){ //freopen("2800.txt","r",stdin); memset(dp,0x3f,sizeof(dp)); memset(vis,false,sizeof(vis)); cin>>n; for(int i=0;i<=n;i++){ for(int j=0;j<=n;j++){ cin>>g[i][j]; } } Floyd(); /*for(int i=0;i<=n;i++){ for(int j=0;j<=n;j++){ cout<<g[i][j]<<‘ ‘; } cout<<endl; }*/ cout<<dfs(0,(1<<n)-1)<<endl; /*int a,b; while(cin>>a>>b){ cout<<dp[a][b]<<endl; }*/ //fclose(stdin); return 0; }
ps:你看到了大量的注释,它们包括深搜算法和Debug(我懒得删去了^_^!)
ps:文字表情太帅了! 来一个最经典的 :)
标签:
原文地址:http://www.cnblogs.com/FuTaimeng/p/5471173.html