TSP[状压DP]

TSP
我的第一道状压DP
洛谷的数据太强了!

用记忆化搜索写了一遍, T 了两个点,开 \(O2\) , 还是 T 一个点;

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int MAXN=21;
int d[1<<MAXN-1][MAXN],dist[MAXN][MAXN];

inline int scanf(int& x)
{
    x=0;char c=getchar();
    while(c<'0'||c>'9'){c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
}
void printf(int x)
{
    int s[23]={0},&top=s[0];
    while(x){s[++top]=x%10;x/=10;}
    if(!top) s[++top]=0;
    while(top) putchar(s[top--]+'0');
}
int dfs(int S,int u,int n)
{
    int &ans=d[S][u];
    if(ans>=0) return ans;
    ans=(1<<30)-1;
    for(int v=0;v<n;v++)
        if((1<<v) & S)
            ans=min(ans,dfs(S^(1<<v),v,n) + dist[u][v]);
    return ans;
}

int main()
{
    int n;
    scanf(n);
    for(int i=0;i<n;i++)
        for(int j=0;j<n;j++) scanf(dist[i][j]);
    
    memset(d,-1,sizeof(d));
    d[0][0]=0;
    int U=(1<<n)-1;
    int ans=dfs(U,0,n);
    printf(ans);
    return 0;
}

于是转到递推,结果搞了半天,被自己设的状态整到了 :

  • \(d[S][u]\)\(S\)中的结点已经走过,现在在结点 \(u\) , 此时的最短路径.
  • \(d[S][u]=min{d[S-{v}][v]+dist(u,v)\ }\ |\ v\in\ S\)
    一直讲答案看做 \(d[U][0]\) , 但实际上当集合枚举到 \(U\) 时 0 已经是"走过的点"了,而转移是是从"未经过的点"中选择一个,因此是不会再转移到 \(d[U][0]\) 的 !
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int MAXN=21;
int d[1<<(MAXN-1)][MAXN],dist[MAXN][MAXN];

inline void read(int *x)
{
    *x=0;
    char  c=getchar();
    while(c<'0' || c>'9') c=getchar();
    while(c>='0' && c<='9'){*x=(*x)*10+c-'0';c=getchar();}
}
inline void write(int x)
{
    int s[19]={0},&top=s[0];
    while(x){s[++top]=x%10;x/=10;}
    if(!top)s[++top]=0;
    while(top)putchar(s[top--]+'0');
}
int main()
{
    int n;
    read(&n);
    for(int i=0; i<n; i++)
        for(int j=0; j<n; j++)
            read(&dist[i][j]);

    memset(d,0x7f,sizeof(d));
    d[1][0]=0;
    int U=(1<<n)-1;
    for(int S=0; S<=U; S++)
        for(int u=0; u<n; u++)
            if(!(S&(1<<u)))
                for(int v=0; v<n; v++)
                    if(S&(1<<v))
                        d[S|(1<<u)][u]=min(d[S|(1<<u)][u],d[S][v]+dist[v][u]);
    
    int ans = (1<<30)-1;
    for(int v=1;v<n;v++) ans=min(ans,d[U][v]+dist[v][0]);
    write(ans);
    return 0;
}

哎,调了半天莫名RE,原来是\(dist,d\)数组弄反了...
果然还是个大蒟蒻啊...

posted @ 2018-10-05 20:15  昤昽  阅读(177)  评论(0编辑  收藏  举报