zoukankan      html  css  js  c++  java
  • P4294 [WC2008]游览计划(斯坦纳树)

    最小斯坦纳树用于处理联通集合中指定的点的最小代价,一般来说可以通过其他不属于集合的点

    最小生成树是特殊的斯坦纳树,它适用于联通集合中的所有点。

    对于斯坦纳树,从两方面考虑他,首先我们定义f[i][s]表示以i为根,联通状态为s的情况

    对于更新,从两个方面考虑,第一个方面,根不变,枚举子集更新当前状态

    第二个方面,子集不变,通过旁边的点来更新当前根

    这两个的顺序不能改变,因为我们要保证在第二种情况更新的时候,当前联通所处的状态已经是最小值

    对于为什么第二步更新必须存在但是只需要更新当前的状态呢。

    有一个合理的解释是,因为更加后面的状态一定会从下一次的第一步来枚举更新出来。但是更新完后,当前状态并不一定是最小值

    因为可能在真实的图上是有路径重叠的,因此我们可以通过其他额外的不在集合中的点来更新他。

    对于第一步,使用状压dp,对于第二步,使用spfa来更新,因为第二步是一个三角不等式,可以进行松弛操作.

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> pll;
    typedef pair<int,pll> plll;
    const int N=1e6+10;
    const int inf=0x3f3f3f3f;
    const int mod=1e9+7;
    int a[20][20];
    int f[20][20][1050];
    int st[20][20];
    struct node{
        int a,b;
        int now;
    }pre[20][20][1050];
    queue<node> q;
    int n,m;
    int dx[]={-1,0,1,0};
    int dy[]={0,1,0,-1};
    void spfa(int state){
        while(q.size()){
            auto t=q.front();
            q.pop();
            st[t.a][t.b]=0;
            int i;
            for(i=0;i<4;i++){
                int x=t.a+dx[i];
                int y=t.b+dy[i];
                if(x&&x<=n&&y&&y<=m){
                    if(f[x][y][state]>f[t.a][t.b][state]+a[x][y]){
                        f[x][y][state]=f[t.a][t.b][state]+a[x][y];
                        pre[x][y][state]={t.a,t.b,state};
                        if(!st[x][y]){
                            q.push({x,y,state});
                            st[x][y]=1;
                        }
                    }
                }
            }
        }
    }
    void dfs(int a,int b,int state){
        if(!a||!b)
            return ;
        st[a][b]=1;
        auto x=pre[a][b][state];
        dfs(x.a,x.b,x.now);
        if(x.a==a&&x.b==b) dfs(x.a,x.b,state-x.now); //因为是从补集转移,因此另一边的补集也要查询
    }
    int main(){
        ios::sync_with_stdio(false);
        cin>>n>>m;
        int i,j;
        int num=0;
        memset(f,0x3f,sizeof f);
        for(i=1;i<=n;i++){
            for(j=1;j<=m;j++){
                cin>>a[i][j];
                if(!a[i][j]){
                    f[i][j][1<<num]=0;
                    num++;
                }
            }
        }
        int all=(1<<num)-1;
        for(int state=0;state<1<<num;state++){
            for(i=1;i<=n;i++){
                for(j=1;j<=m;j++){
                    for(int s=state;s;s=(s-1)&state){
                        if(f[i][j][state]>f[i][j][s]+f[i][j][state-s]-a[i][j]){
                            f[i][j][state]=f[i][j][s]+f[i][j][state-s]-a[i][j];
                            pre[i][j][state]={i,j,s};
                        }
                    }
                    if(f[i][j][state]<inf){
                        st[i][j]=1;
                        q.push({i,j,state});
                    }
                }
            }
            spfa(state);
        }
        int ans=0x3f3f3f3f;
        int be=0,ed=0;
        for(i=1;i<=n;i++){
            for(j=1;j<=m;j++){
                if(f[i][j][all]<ans){
                    ans=f[i][j][all];
                    be=i,ed=j;
                }
            }
        }
        memset(st,0,sizeof st);
        dfs(be,ed,all);
        cout<<ans<<endl;
        for(i=1;i<=n;i++){
            for(j=1;j<=m;j++){
                if(!a[i][j]) cout<<"x";
                else{
                    if(st[i][j]) cout<<"o";
                    else cout<<"_";
                }
            }
            cout<<endl;
        }
        return 0;
    }
    View Code
    没有人不辛苦,只有人不喊疼
  • 相关阅读:
    [ 打败 IE 的葵花宝典 ] IE6中css常见BUG全集及解决方案
    js获取URl传递的参数
    几种C#框架提供的数据结构对单值查找的效率比较
    C#Hashtable与Dictionary性能
    Sql server 使用存储过程分页显示
    arrayList使用 与 foreach 使用
    LeetCode 047. 全排列 II DFS
    LeetCode 046. 全排列 dfs 和 dfs_swap
    LeetCode 048. 旋转图像
    LeetCode 040. 组合总和 II 非SET去重
  • 原文地址:https://www.cnblogs.com/ctyakwf/p/13556647.html
Copyright © 2011-2022 走看看