luoguP4294 [WC2008]游览计划 斯坦纳树

本文深入探讨了状压动态规划(DP)与最短路径更快算法(SPFA)的结合应用,通过具体实例讲解如何求解带状态压缩的最短路径问题,并附有详细代码实现。适用于对算法有一定基础并希望深入了解高级算法技巧的读者。

这个其实就是状压DP+spfa.    

本题需要输出方案,有一点点麻烦 

code:   

#include <bits/stdc++.h>     
#define ll long long 
#define N 12     
#define inf 0x3f3f3f3f
#define setIO(s) freopen(s".in","r",stdin)  
using namespace std;      
int dx[]={0,-1,0,1};   
int dy[]={-1,0,1,0};          
int n,m,K=0,tot;    
int val[N][N];   
int bin[N],f[N*N][1<<N],id[N][N],X[N*N],Y[N*N],v[N*N],inq[N*N];              
struct node 
{
    int pos,s;   
    node(int pos=0,int s=0):pos(pos),s(s){}  
}pre[N*N][1<<N];        
queue<int>q;      
void solve(int cur) 
{
    while(!q.empty()) 
    {
        int u=q.front(); 
        q.pop(),inq[u]=0;   
        int x=X[u],y=Y[u];    
        for(int i=0;i<4;++i) 
        {
            int xx=x+dx[i]; 
            int yy=y+dy[i]; 
            if(!(xx>=1&&xx<=n&&yy>=1&&yy<=m)) 
                continue;      
            int to=id[xx][yy];    
            if(f[to][cur]>f[u][cur]+v[to]) 
            {
                f[to][cur]=f[u][cur]+v[to];        
                pre[to][cur]=node(u,cur);      
                if(!inq[to]) 
                {
                    inq[to]=1;     
                    q.push(to);     
                }
            }
        }
    }
}     
int mk[N][N];   
void dfs(int x,int now) 
{    
    mk[X[x]][Y[x]]=1;    
    if(!pre[x][now].pos)   
        return;     
    if(pre[x][now].pos==x)   
        dfs(x,now^pre[x][now].s);    
    dfs(pre[x][now].pos,pre[x][now].s);   
}
int main() 
{ 
    // setIO("input");     
    int i,j,rr=0;     
    scanf("%d%d",&n,&m);   
    for(i=1;i<N;++i)  
        bin[i]=1<<(i-1);     
    for(i=1;i<=n;++i)   
        for(j=1;j<=m;++j)  
            id[i][j]=++tot,X[id[i][j]]=i,Y[id[i][j]]=j;     
    memset(f,0x3f,sizeof(f));      
    for(i=1;i<=n;++i)   
        for(j=1;j<=m;++j)   
        {
            scanf("%d",&val[i][j]);      
            v[id[i][j]]=val[i][j];  
            if(!val[i][j])    
            {
                ++K;      
                rr=id[i][j];                  
                f[id[i][j]][bin[K]]=0;  
            }    
        }
    for(i=1;i<bin[K+1];++i) 
    {                       
        for(int pos=1;pos<=tot;++pos)     
        {
            for(j=i&(i-1);j;j=i&(j-1)) 
            {
                if(f[pos][j]+f[pos][i^j]-v[pos]<f[pos][i]) 
                {  
                    f[pos][i]=f[pos][j]+f[pos][i^j]-v[pos];    
                    pre[pos][i]=node(pos,j);         
                }   
            }      
            if(f[pos][i]<inf)   
            {     
                inq[pos]=1;   
                q.push(pos);    
            }
        }         
        solve(i);    
    }
    printf("%d\n",f[rr][bin[K+1]-1]); 
    dfs(rr,bin[K+1]-1);   
    for(i=1;i<=n;++i) 
    {
        for(j=1;j<=m;++j)   
        {
            if(!val[i][j])   
            { 
                printf("x");     
            }
            else 
            { 
                if(mk[i][j])   printf("o");       
                else printf("_"); 

            }
        }
        printf("\n"); 
    }      
    return 0;
}

  

下载前可以先看下教程 https://pan.quark.cn/s/16a53f4bd595 小天才电话手表刷机教程 — 基础篇 我们将为您简单的介绍小天才电话手表新机型的简单刷机以及玩法,如adb工具的使用,magisk的刷入等等。 我们会确保您看完此教程后能够对Android系统有一个最基本的认识,以及能够成功通过magisk root您的手表,并安装您需要的第三方软件。 ADB Android Debug Bridge,简称,在android developer的adb文档中是这么描述它的: 是一种多功能命令行工具,可让您与设备进行通信。 该命令有助于各种设备操作,例如安装和调试应用程序。 提供对 Unix shell 的访问,您可以使用它在设备上运行各种命令。 它是一个客户端-服务器程序。 这听起来有些难以理解,因为您也没有必要去理解它,如果您对本文中的任何关键名词产生疑惑或兴趣,您都可以在搜索引擎中去搜索它,当然,我们会对其进行简单的解释:是一款在命令行中运行的,用于对Android设备进行调试的工具,并拥有比一般用户以及程序更高的权限,所以,我们可以使用它对Android设备进行最基本的调试操作。 而在小天才电话手表上启用它,您只需要这么做: - 打开拨号盘; - 输入; - 点按打开adb调试选项。 其次是电脑上的Android SDK Platform-Tools的安装,此工具是 Android SDK 的组件。 它包括与 Android 平台交互的工具,主要由和构成,如果您接触过Android开发,必然会使用到它,因为它包含在Android Studio等IDE中,当然,您可以独立下载,在下方选择对应的版本即可: - Download SDK Platform...
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值