状压DP hunter

最近想再学学状压DP
hunter
hdu 4568
借鉴了
http://www.cnblogs.com/whatbeg/p/3962180.html
的代码
自己为温习堆优化的dijkstra 写了一个更长的
作为 第一步吧

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#define ll long long
#define oo 1000000007
#define i2 (i<<1)
#define i3 ((i<<1)|1)
using namespace std;
int tot,T,n,m,sz,k;
int d[50005],dis[20][20],dp[1<<17][20],a[205][205];
struct node
{
    int x,y;    
}p[20];
const int dx[4]={1,0,0,-1};
const int dy[4]={0,1,-1,0};
int Next[200005],to[200005],len[200005],head[50005];
void add(int x,int y,int z)
{
    Next[tot]=head[x];
    to[tot]=y;
    len[tot]=z;
    head[x]=tot++;
}
int pos[50005],hp[50005];
void put(int x)
{
    hp[++sz]=x;pos[x]=sz;
    int i=sz;
    while (i>>1)
    {
        int u=hp[i],v=hp[i>>1];
        if (d[u]<d[v])
            swap(pos[u],pos[v]),swap(hp[i],hp[i>>1]);
        else break;
        i>>=1;
    }
}
int get()
{
    int ret=hp[1];
    hp[1]=hp[sz--];
    int i=1,j;
    while (i2<=sz)
    {
        int u=hp[i2],v=hp[i3];
        if (i3>sz || d[u]<d[v]) j=i2;
        else j=i3;
        u=hp[i],v=hp[j];
        if (d[u]>d[v])
        {
            swap(pos[u],pos[v]);
            swap(hp[i],hp[j]);
            i=j;
        }
        else break;
    }
    return ret;
}
void ajust(int x)
{
    int i=pos[x];
    while (i>>1)
    {
        int u=hp[i],v=hp[i>>1];
        if (d[u]<d[v])
            swap(pos[u],pos[v]),swap(hp[i],hp[i>>1]);
        else break;
        i>>=1;
    }
}
void heapdij(int st)
{
    for (int i=0;i<=n*m+1;i++) 
    {
        d[i]=oo;
        pos[i]=0;
    }
    d[st]=0;
    put(st);
    while (sz)
    {
        int x=get();pos[x]=0;
        for (int i=head[x];i!=-1;i=Next[i])
        {
            int y=to[i],z=len[i];
            if (d[x]+z<d[y])
            {
                d[y]=d[x]+z;
                if (!pos[y]) put(y);
                else ajust(y);
            }
        }
    }
}
int main()
{
    scanf("%d",&T);
    while (T--)
    {
        scanf("%d%d",&n,&m);
        for (int i=1;i<=n;i++)
            for (int j=1;j<=m;j++)
            {
                scanf("%d",&a[i][j]);
                if (a[i][j]==-1)
                    a[i][j]=oo;
            }
        tot=0;
        memset(head,-1,sizeof(head));
        for (int i=1;i<=n;i++)
            for (int j=1;j<=m;j++)
            {
                int now=(i-1)*m+j;
                for (int h=0;h<4;h++)
                {
                    int nx=i+dx[h],ny=j+dy[h];
                    if (nx>=1 && nx<=n && ny>=1 && ny<=m)
                    {
                        int tmp=(nx-1)*m+ny;
                        add(now,tmp,a[nx][ny]);     
                    }       
                }
                if (i==1 || i==n || j==1 || j==m)
                {
                    add(0,now,a[i][j]);
                    add(now,n*m+1,0);
                }
            }
            scanf("%d",&k);
            p[0].x=1,p[0].y=0;
            p[k+1].x=n,p[k+1].y=m+1;
            for (int i=1;i<=k;i++)
            {
                scanf("%d%d",&p[i].x,&p[i].y);
                p[i].x++;p[i].y++;
            }
            for (int i=0;i<=k+1;i++)
            {
                int st=(p[i].x-1)*m+p[i].y;
                sz=0;
                heapdij(st);
                for (int j=0;j<=k+1;j++)
                {
                    if (i==j) continue;
                    int tmp=(p[j].x-1)*m+p[j].y;
                    dis[i][j]=d[tmp];
                }
            }
            for (int i=0;i<(1<<16);i++)
                for (int j=0;j<16;j++)
                    dp[i][j]=oo;
            for (int i=0;i<k;i++)
                dp[1<<i][i+1]=dis[0][i+1];
            for (int i=0;i<(1<<k);i++)
            {
                for (int kk=0;kk<k;kk++)
                {
                    if (!(i&(1<<kk))) continue;
                    for (int j=0;j<k;j++)
                    {
                        if (i&(1<<j)) continue;
                        dp[i+(1<<j)][j+1]=min(dp[i+(1<<j)][j+1],dp[i][kk+1]+dis[kk+1][j+1]);
                    }
                }
            }
        int ans=oo;
        for (int i=1;i<=k;i++)
            ans=min(ans,dp[(1<<k)-1][i]+dis[i][k+1]);
        if (ans==oo) printf("0\n");
        else printf("%d\n",ans);        
    }
    return 0;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值