【TopCoderSRM 470C】BuildingRoads(斯坦纳树)

版权声明

IcePrincess的博客基础上略加改动。


题目链接

【TopCoderSRM 470C】BuildingRoads


题目大意

在每一对由同一个字符表示的城市之间建立一条道路,求所需的最低成本。


题解

斯坦纳树裸题
将指定点集合中的所有点连通,且边权总和最小的生成树称为最小斯坦纳树(Minimal Steiner Tree),其实最小生成树是最小斯坦纳树的一种特殊情况。而斯坦纳树可以理解为使得指定集合中的点连通的树,但不一定最小。
斯坦纳树是用于解决这种问题的:给定若干关键点,求使得关键点连通的最小代价。

dp[i][j][mask] d p [ i ] [ j ] [ m a s k ] 表示当前在 (i,j) ( i , j ) ,当前已经在树中的节点为 mask m a s k 的最小代价。
两种转移
1. dp[i][j][mask]=min(dp[i][j][mask],dp[i][j][sub]+dp[i][j][mask-sub])
2. dp[i][j][mask]=min(dp[i][j],dp[i'][j'][mask]+score[a[i][j]]),其中 (i,j) ( i , j ) (i,j) ( i ′ , j ′ ) 相邻,这个可以用 spfa s p f a 转移。

注意若干相同的字母连通是一块石头,所以 spfa s p f a 的时候注意一下
注意最后求的不是一棵斯坦纳树而是一个斯坦纳森林。
所以还要再来一个 dp d p f[mask] f [ m a s k ] 表示在 mask m a s k 状态下最少多少代价可以生成斯坦纳森林。

f[mask]=min(f[mask],f[i][j][mask],f[sub]+f[masksub]) f [ m a s k ] = m i n ( f [ m a s k ] , f [ i ] [ j ] [ m a s k ] , f [ s u b ] + f [ m a s k − s u b ] ) ,其中 sub s u b masksub m a s k − s u b 要是合法 mask m a s k ,即要求相连的点对要成对出现。

代码

#include <cstdio>  
#include <iostream>  
#include <cstring>  
#include <string>  
#include <cstdlib>  
#include <utility>  
#include <cctype>  
#include <algorithm>  
#include <bitset>  
#include <set>  
#include <map>  
#include <vector>  
#include <queue>  
#include <deque>  
#include <stack>  
#include <cmath>  
#define LL long long  
#define LB long double  
#define x first  
#define y second  
#define Pair pair<int,int>  
#define pb push_back  
#define pf push_front  
#define mp make_pair  
#define LOWBIT(x) x & (-x)  
using namespace std;  

const int MOD=1e9+7;  
const LL LINF=2e16;  
const int INF=1e9;  
const int magic=348;  
const double eps=1e-10;  
const double pi=3.14159265;  

inline int getint()  
{  
    char ch;int res;bool f;  
    while (!isdigit(ch=getchar()) && ch!='-') {}  
    if (ch=='-') f=false,res=0; else f=true,res=ch-'0';  
    while (isdigit(ch=getchar())) res=res*10+ch-'0';  
    return f?res:-res;  
}  

int score[300];  
int dp[51][51][1024],Dp[1024],DP[1024];  
char table[48];  
int n,m,k;  
int dx[]={-1,0,1,0},dy[]={0,1,0,-1};  

struct BuildingRoads  
{  
    inline void Clear()  
    {  
        int i,j,Mask;  
        for (i=1;i<=n;i++)  
            for (j=1;j<=m;j++)  
                for (Mask=0;Mask<=(1<<k)-1;Mask++)  
                    dp[i][j][Mask]=INF;  
        for (Mask=0;Mask<=(1<<k)-1;Mask++) Dp[Mask]=DP[Mask]=INF;  
    }  
    inline void init_score()  
    {  
        memset(score,0,sizeof(score));  
        score['.']=0;  
        for (int i=1;i<=26;i++) score['a'+i-1]=i;  
        for (int i=1;i<=26;i++) score['A'+i-1]=i*100;  
        for (int i=1;i<=9;i++) score['0'+i]=i*10000;  
        score['0']=100000;  
    }  
    inline bool check_home(char ch)  
    {  
        if (ch=='!' || ch=='@' || ch=='#' || ch=='$') return true;  
        return false;  
    }  
    bool inq[51][51];queue<int> q;  
    char Mp[148][148];  
    inline void spfa(int Mask)  
    {  
        int i,x,y,xx,yy;  
        while (!q.empty())  
        {  
            x=q.front();q.pop();y=q.front();q.pop();inq[x][y]=false;  
            for (i=0;i<=3;i++)  
            {  
                xx=x+dx[i];yy=y+dy[i];  
                if (xx<1 || xx>n || yy<1 || yy>m) continue;  
                int add=(Mp[x][y]==Mp[xx][yy]?0:score[Mp[xx][yy]]);  
                if (dp[xx][yy][Mask]>dp[x][y][Mask]+add)  
                {  
                    dp[xx][yy][Mask]=dp[x][y][Mask]+add;  
                    if (!inq[xx][yy]) inq[xx][yy]=true,q.push(xx),q.push(yy);  
                }  
            }  
        }  
    }  
    inline bool check_Mask(int Mask)  
    {  
        int visited[248];memset(visited,0,sizeof(visited));  
        int i;  
        for (i=1;i<=k;i++) if (Mask&(1<<(i-1))) visited[table[i]]^=1;  
        for (i=0;i<=200;i++) if (visited[i]) return false;  
        return true;  
    }  
    int destroyRocks(vector<string> a)  
    {  
        int i,j,Mask,sub,cc=0;  
        n=int(a.size());m=int(a[0].size());  
        k=0;  
        for (i=1;i<=n;i++)  
            for (j=1;j<=m;j++)  
                if (check_home(a[i-1][j-1])) k++;  
        for (i=1;i<=n;i++)  
            for (j=1;j<=m;j++)  
                Mp[i][j]=a[i-1][j-1];  
        init_score();Clear();  
        for (i=1;i<=n;i++)  
            for (j=1;j<=m;j++)  
                if (check_home(a[i-1][j-1])) dp[i][j][1<<(cc++)]=0,table[cc]=a[i-1][j-1];  
        for (Mask=1;Mask<=(1<<k)-1;Mask++)  
        {  
            for (i=1;i<=n;i++)  
                for (j=1;j<=m;j++)  
                {  
                    for (sub=(Mask-1)&Mask;sub;sub=Mask&(sub-1))  
                        if (dp[i][j][sub]+dp[i][j][Mask-sub]-score[Mp[i][j]]<dp[i][j][Mask])  
                            dp[i][j][Mask]=dp[i][j][sub]+dp[i][j][Mask-sub]-score[Mp[i][j]];  
                    if (dp[i][j][Mask]<INF) inq[i][j]=true,q.push(i),q.push(j);  
                }  
            spfa(Mask);  
        }  
        for (Mask=1;Mask<=(1<<k)-1;Mask++)  
            for (i=1;i<=n;i++)  
                for (j=1;j<=m;j++)  
                    Dp[Mask]=min(Dp[Mask],dp[i][j][Mask]);  
        for (Mask=1;Mask<=(1<<k)-1;Mask++)  
        {  
            DP[Mask]=Dp[Mask];  
            for (sub=Mask&(Mask-1);sub;sub=Mask&(sub-1))  
                if (check_Mask(sub) && check_Mask(Mask-sub)) DP[Mask]=min(DP[Mask],DP[sub]+DP[Mask-sub]);  
        }  
        return DP[(1<<k)-1];  
    }  
};  
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值