hdu 4569 TSP

不得不说状态压缩是个很神奇的东西,学习了一天终于稍微学懂了,这个问题,

首先,旅行商问题状态转移方程 dp[i][j] 表示经过第i个点,第j个状态

dp[i][j] = min (dp[i][j],dp[prei][j - (1<<i)] + cost);

这只是第一道。。。还会待续的

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
const int M = 232;
const int inf = 1e10;
int dis[M*M],n,m;
int map[M][M],dp[20][1<<16],user[M*M],tre[M][M],go[M][M],cost[M],vis[M*M];
struct Node{
    int i,dis;
    Node(){};
    Node (int a,int b){
    i = a;dis = b;
    }
    bool operator < (const Node& a)const{
        return dis > a.dis;
    }
};
int dx[4] = {-1,1,0,0};
int dy[4] = {0,0,1,-1};
void dij(int st,int pos){
    priority_queue<Node> Q;
    Q.push(Node(st,0));
    memset(vis,0,sizeof(vis));
    for(int i=0;i<=n*m;i++)
        dis[i] = inf;
    dis[st] = 0;
    Node it;

    while(!Q.empty()){
        it = Q.top();Q.pop();
        int u = it.i ;
        if(vis[u])continue;
        vis[u] = 1;
        int x = u /m,y = u%m;
        if(tre[x][y] != -1) go[pos][tre[x][y]] = dis[u];
        if(x==0||y==0||x==n-1||y==m-1){
            cost[pos] = min(cost[pos],dis[u]);
        }
        for(int d=0;d<4;d++)
        {
            int nx = dx[d]+x;
            int ny = dy[d]+y;
            if(map[nx][ny] == -1)continue;
            if(nx < 0||nx >= n||ny < 0 || ny >=m)continue;
            int uu  = nx * m+ny;
            if(dis[uu] > dis[u]+map[nx][ny]){
                dis[uu] = dis[u] + map[nx][ny];
                Q.push(Node(uu,dis[uu]));
            }
        }
    }
}
int main()
{
    int k,x,y;
    int T;
    scanf("%d",&T);
    while(T--) {
        memset(tre,-1,sizeof(tre));
        scanf("%d%d",&n,&m);
        for(int i=0;i<n;i++)
            for(int j=0;j<m;j++)
                scanf("%d",&map[i][j]);
            scanf("%d",&k);
            memset(go,63,sizeof(go));
            for(int i=0;i<k;i++){
                scanf("%d%d",&x,&y);
                //go[i][i] = 0;
                tre[x][y] = i;
                user[i] = x * m + y;
            }
            for(int i=0;i<k;i++){
                go[i][i] = 0 ;
                cost[i] = inf;
                dij(user[i],i);
            }
            memset(dp,63,sizeof(dp));
            for(int i=0;i<k;i++){
                x = user[i] / m;
                y = user[i] % m;
                dp[i][1<<i] = cost[i] + map[x][y];
            }
            for(int j=0;j<(1<<k);j++){
                for(int i=0;i<k;i++){
                    //if(j&(1<<i)&&j!=(1<<i))
                   if((j&(1<<i)) == 0) continue;
                  // if(dp[i][j] == inf) continue;

                    for(int s = 0;s<k;s++){
                        if((j & (1 << s)) == 0) continue;
                        dp[i][j] = min(dp[i][j],dp[s][j-(1<<i)]+go[s][i]);
                    }
                }
            }
            int ans = inf;
            for(int i=0;i<k;i++){
                ans = min(dp[i][(1<<k)-1]+cost[i],ans);
            }

       printf("%d\n",ans);
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值