斯坦纳树DP

斯坦纳树:

主要是DP思想,转化成联通图求最短联通K个点的路径后,可以状态压缩,DP转移分2步,一步本节点合并,一步最短路松弛。另外可以输出路径,注意回溯时\(dp[i][j][s]\)可以由\(dp[i][j][t]和dp[i][j][s-t]\)转移,需要判断一下



#include<bits/stdc++.h>
using namespace std;
#define _f(i,a,b) for(register int i=a;i<=b;++i)
#define f_(i,a,b) for(register int i=a;i>=b;--i)
#define chu printf
#define ll long long
#define ull unsigned long long
inline ll re()
{
    ll x=0,h=1;
    char ch=getchar();
    while(ch<'0'||ch>'9')
    {
        if(ch=='-')h=-1;
        ch=getchar();
    }
    while(ch<='9'&&ch>='0')
    {
        x=(x<<1)+(x<<3)+(ch^48);
        ch=getchar();
    }
    return x*h;
}
const int N=1e5+100;
int n,m;
int a[12][12],dp[12][12][(1<<10)+100];
int cnt;
struct Node
{
    int x,y,s;int dap;
    Node(){}
    Node(int xx,int yy,int ss,int ddpp)
    {
        x=xx;y=yy;s=ss;dap=ddpp;
    }
    Node(int xx,int yy,int ss)
    {
        x=xx;y=yy;s=ss;
    }
    bool operator<(const Node&A)const
    {
        return dap>A.dap;//让小的先来
    }
};
priority_queue<Node >q;//点对
Node last[12][12][(1<<10)+100];
int xd[5]={0,1,0,-1};
int yd[5]={1,0,-1,0};
int tpx,tpy,vis[11][11],ans[11][11];
//ans记录装什么,ans(i,j)=1代表是景点,ans(i,j)=2代表要有志愿者
inline void Dij(int s)
{
    memset(vis,0,sizeof(vis));
    while(!q.empty())
    {
        
        Node ls=q.top();q.pop();
        if(vis[ls.x][ls.y])continue;
        vis[ls.x][ls.y]=1;
       // chu("%d %d\n",ls.x,ls.y);
        Node nw;
        _f(i,0,3)
        {
            nw.x=ls.x+xd[i];
            nw.y=ls.y+yd[i];
            if(nw.x>n||nw.y>m||nw.x==0||nw.y==0)continue;
            nw.dap=ls.dap+a[nw.x][nw.y];
            if(nw.dap<dp[nw.x][nw.y][s])
            {
                dp[nw.x][nw.y][s]=nw.dap;
                last[nw.x][nw.y][s]=Node(ls.x,ls.y,s);
                q.push(nw);
            }
        }
    }
}
inline void getans(int x,int y,int s)
{
    if(last[x][y][s].s==0)return;
    Node ls=last[x][y][s];
   // chu("go last:%d %d\n",ls.x,ls.y);
    if(a[ls.x][ls.y])
    {
        ans[ls.x][ls.y]=1;
     //   chu("mark:%d %d\n",ls.x,ls.y);
    }
    getans(ls.x,ls.y,ls.s);
    if(ls.x==x&&ls.y==y)getans(x,y,s-ls.s);
}
int main()
{
    n=re(),m=re();
    memset(dp,0x3f,sizeof(dp));
    _f(i,1,n)
    _f(j,1,m)
    {
        a[i][j]=re();
        if(!a[i][j])++cnt,dp[i][j][1<<(cnt-1)]=0,tpx=i,tpy=j;
    }
    _f(s,0,(1<<cnt)-1)
    {
        //chu("out\n");
        _f(i,1,n)
        _f(j,1,m)
        {
            for(int k=s&(s-1);k;k=((k-1)&(s)))
            {
                //chu("jwo\n");
                if(dp[i][j][s]>dp[i][j][k]+dp[i][j][s-k]-a[i][j])//如果是景点也一样,不能算2次
                dp[i][j][s]=dp[i][j][k]+dp[i][j][s-k]-a[i][j],
                last[i][j][s]=Node(i,j,k);
            }
            if(dp[i][j][s]<0x3f3f3f3f)q.push(Node(i,j,s,dp[i][j][s]));
        }
        Dij(s);
      //  chu("s:%d\n",s);
    }
    chu("%d\n",dp[tpx][tpy][(1<<cnt)-1]);
    getans(tpx,tpy,(1<<cnt)-1);
    _f(i,1,n)
    {
        _f(j,1,m)
        {
            if(!a[i][j])chu("x");
            else if(ans[i][j])chu("o");
            else chu("_");
        }
        chu("\n");
    }
    return 0;
}
/*
4 4 
0 1 1 0 
2 5 5 1 
1 5 5 1 
0 1 1 0

*/
posted on 2022-09-12 18:31  HZOI-曹蓉  阅读(59)  评论(0)    收藏  举报