hdu 4568 旅行商问题dp

这个题目题意描述不清,没有说明只能进入一次。

题目意思很好理解,不再重复。

思路也比较好想,先计算每两个宝藏区的最短路,和每个宝藏区到边界的最短路,然后dp解决。

在计算最短路的时候,用优先队列优化的Dijkstra算法。

在-1的处理上有些小技巧。

但是!但是!!,我之前的思路是dp[i]表示状态i的最小cost值,并没有经过严格证明和认真思考导致wa好多次。实际上这个思路在计算过程中会导致信息丢失,下次动键盘前一定要证明一下。。

正确的状态转移应该是用dp[i][j]表示状态i并以第j个宝藏结尾的最小cost,这样每一步计算就保存了足够多的信息了。

话说这就是所谓的旅行商问题了。

#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
int data[202][202];
int min_d[14][14],tmp_d[202][202];
int out_d[14],k,x[14],y[14];
int Gold[202][202];
int T,n,m;
const int mx[4]={1,0,-1,0},my[4]={0,1,0,-1};
const int INF = 1000000;
struct D{
    int x,y;
    int d;
    D(int gx,int gy,int gd){
        x=gx;y=gy;d=gd;
    }
};
bool operator < (D a,D b) {
    return a.d>b.d;
}
void cal_min_d_out_d() {
    priority_queue<D> que;
    memset(min_d,0,sizeof(min_d));
    for(int i=0;i<k;i++) out_d[i]=INF;
    for(int i=0;i<k;i++) {
        bool visd[202][202];
        memset(visd,0,sizeof(visd));
        tmp_d[x[i]][y[i]]=data[x[i]][y[i]];
        que.push(D(x[i],y[i],data[x[i]][y[i]]));
        visd[x[i]][y[i]]=true;
        if(x[i]==0||x[i]==n-1||y[i]==0||y[i]==m-1) out_d[i]=0;
        while(!que.empty()) {
            D tmp = que.top();
            que.pop();
            int xx=tmp.x,yy=tmp.y;
            for(int j=0;j<4;j++) {
                int tx=xx+mx[j],ty=yy+my[j];
                if(tx>=0&&tx<n&&ty>=0&&ty<m&&data[tx][ty]!=-1&&!visd[tx][ty]) {
                    tmp_d[tx][ty]=tmp_d[xx][yy]+data[tx][ty];
                    que.push(D(tx,ty,tmp_d[tx][ty]));
                    visd[tx][ty]=true;
                    if(Gold[tx][ty]) min_d[i][Gold[tx][ty]-1] = tmp_d[tx][ty]-data[tx][ty];
                    if(tx==0||ty==0||tx==n-1||ty==m-1) out_d[i]=min(out_d[i],tmp_d[tx][ty]-data[x[i]][y[i]]);
                }
            }
        }
    }
}

int main()
{

    scanf("%d",&T);
    while(T--) {
        int oo=0;
        scanf("%d%d",&n,&m);
        for(int i=0;i<n;i++)
        for(int j=0;j<m;j++) {
            scanf("%d",&data[i][j]);
        }
        scanf("%d",&k);
        memset(Gold,0,sizeof(Gold));
        for(int i=0;i<k;i++) {
            scanf("%d%d",&x[i],&y[i]);
            if(data[x[i]][y[i]]==-1) {
                i--;
                k--;
                continue;
            }
            Gold[x[i]][y[i]]=i+1;
        }
        cal_min_d_out_d();
        int dp[1<<k][k+1];
        for(int i=0;i<(1<<k);i++)
            for(int j=0;j<k;j++)
            dp[i][j]=INF;

        for(int i=0;i<k;i++) {
            dp[1<<i][i]=out_d[i]*2+data[x[i]][y[i]];
            if(dp[1<<i][i]>=INF) {
                dp[1<<i][i]=0;
                oo=(1<<i)|oo;
            }
        }
        for(int i=3;i<(1<<k);i++) {
        for(int j=0;j<k;j++) {
            if(i&oo) continue;
            if(dp[i][j]!=INF) continue;
            int t=1<<j,th=0;
            if(t&i){
                int pre=i&(i^t);
                for(int jj=0;jj<k;jj++) {
                    dp[i][j]=min(dp[i][j],dp[pre][jj]-out_d[jj]+out_d[j]+min_d[j][jj]);
                }
            }
        }
        }
        int ans=INF;
        for(int i=0;i<k;i++) ans=min(dp[oo^((1<<k)-1)][i],ans);
        printf("%d
",ans);
    }
}
原文地址:https://www.cnblogs.com/lastone/p/5281238.html