hihocoder #1608 : Jerry的奶酪(状压DP)

传送门

题意

分析

设dp[i][j]为在i状态下当前在第j个奶酪的最小费用
转移方程:dp[(1<<k)|i][k]=dp[i][j]+d[j][k]
预处理出每个奶酪之间的距离,加入起点与终点

不以获取奶酪为目标的移动是无意义的
预处理出起点、终点以及奶酪之间的最短路径????[?][?]
起点的编号为?,终点的编号为?+1
?[?≤?<?+?][?≤?<?^? ]
?表示当前处于起点/终点/第几块奶酪,?表示已经获取的奶酪情况
初始状态?[?][0]=0,最后答案?[?+1][2^?−1]
转移——?[?][?]+????[?][?^′ ]→?[?^′ ][? ?? ?^(?^′ ) (如果?^′<?)]
使用类似最短路的方式进行动态规划
?(???+??^? )

trick

外循环为状态,内循环为奶酪编号

代码

#include <bits/stdc++.h>
using namespace std;

#define ll long long
#define F(i,a,b) for(int i=a;i<=b;++i)
#define R(i,a,b) for(int i=a;i<b;++i)
#define mem(a,b) memset(a,b,sizeof(a))

int n,m,k;
char s[303][303];
int dp[5050][15];
int dis[303][303];
int d[15][15];
int x[15],y[15];
int a[4][2]={0,1,1,0,0,-1,-1,0};
queue<pair<int,int> >q;
void bfs(int sx,int sy)
{
    dis[sx][sy]=0;
    while(!q.empty())q.pop();
    q.push(make_pair(sx,sy));
    while(!q.empty())
    {
        pair<int,int>tmp=q.front();q.pop();
        int x=tmp.first,y=tmp.second;
        R(i,0,4)
        {
            int xx=x+a[i][0],yy=y+a[i][1];
            if(xx<0||xx>=n||yy<0||yy>=m||s[xx][yy]=='1') continue;
            if(dis[xx][yy]==-1)
            {
                dis[xx][yy]=dis[x][y]+1;
                q.push(make_pair(xx,yy));
            }
        }
    }
}
int main()
{
    scanf("%d%d%d",&n,&m,&k);
    R(i,0,n) scanf("%s",s[i]);
    F(i,1,k) scanf("%d%d",x+i,y+i);
    x[0]=0,y[0]=0,x[++k]=n-1,y[k]=m-1;
    F(i,0,k)
    {
        mem(dis,-1);
        bfs(x[i],y[i]);
        F(j,0,k) d[i][j]=dis[x[j]][y[j]];
    }
    mem(dp,-1);
    dp[0][0]=0;
    //F(i,0,k)F(j,0,k) printf("%d%c",d[i][j],j==k?'\n':' ' );
    R(i,0,(1<<(k+1)))F(j,0,k) if(dp[i][j]!=-1)
    {
        F(q,0,k)
        {
            int ret=i|(1<<q);
            if(d[j][q]!=-1&&(dp[ret][q]==-1||dp[ret][q]>dp[i][j]+d[j][q]))
                dp[ret][q]=dp[i][j]+d[j][q];
        }
    }
    printf("%d\n",dp[(1<<(k+1))-1][k] );
    return 0;
}

转载于:https://www.cnblogs.com/chendl111/p/7684081.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值