• 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);
        }
    }
  • 相关阅读:
    18.06.30 POJ 2488:A Knight's Journey
    18.06.27 POJ 3414:Pots
    18.06.27 15年期末Stupid cat & Doge
    18.06.27 水题整理(3)--1st 上机
    18.6.27 水题整理(2)--2nd 上机
    18.6.27 一些没放上来的水题整理(1)--3rd 上机
    18.06.27 POJ NOI 7217猴子吃桃
    18.06.27 POJ NOI 4977怪盗基德的滑翔翼
    18.06.27 POJ百练 4124海贼王之伟大航路
    18.06.27 POJ1054 The Troublesome Frog
  • 原文地址:https://www.cnblogs.com/lastone/p/5281238.html
Copyright © 2020-2023  润新知