hdu 4568 旅行商问题dp

来源:互联网 发布:杭州汉聚网络怎么样 编辑:程序博客网 时间:2024/04/28 16:57
这个题目题意描述不清,没有说明只能进入一次。

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

思路也比较好想,先计算每两个宝藏区的最短路,和每个宝藏区到边界的最短路,然后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\n",ans);    }}
0 0
原创粉丝点击