斯坦纳树模板

屌炸天阿什么东西都有 丢

//斯坦纳树模板 让k个点联通的最小生成树 复杂度 n*3^k
#include<iostream>
#include<cstring>
#include<set>
#include<map>
#include<cmath>
#include<stack>
#include<queue>
#include<deque>
#include<list>
#include<algorithm>
#include<stdio.h>
#include<iomanip>

#define rep(i,n) for(int i=0;i<n;++i)
#define fab(i,a,b) for(int i=a;i<=b;++i)
#define fba(i,b,a) for(int i=b;i>=a;--i)
#define PB push_back
#define INF 0x3f3f3f3f
#define MP make_pair
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define sf scanf
#define pf printf
#define LL long long
const int N=55;
using namespace std;
typedef pair<int,int>PII;
int n,m,k;
queue<int>Q;
int dp[N][1<<10],st[N],all;
bool  vis[N][1<<10];
int dpans[1<<10];
const int M =10010;
int head[N];
int to[M],next[M],cost[M];
int e;
void init(){
    memset(head,-1,sizeof head);
    while(!Q.empty())Q.pop();
    e=0;
}
void addedge(int u,int v,int w){
    to[e]=v;
    cost[e]=w;
    next[e]=head[u];
    head[u]=e++;
}
void input(){
    sf("%d%d%d",&n,&m,&k);
    rep(i,m){
        int u,v,w;
        sf("%d%d%d",&u,&v,&w);
        u--;v--;
        addedge(u,v,w);
        addedge(v,u,w);
    }
}
void stma_init(){
    all=(1<<(2*k));
    rep(i,n)rep(j,all)dp[i][j]=INF;
    memset(st,0,sizeof st);
    memset(vis,0,sizeof vis);
    rep(i,k){
        st[i]=(1<<i);
        st[n-k+i]= (1<<(i+k));
        dp[i][st[i]]=0;
        dp[n-k+i][st[n-k+i]]=0;
    }
}

void spfa(int state){
    while(!Q.empty()){
        int u=Q.front();Q.pop();
        vis[u][state]=false;
        for(int p=head[u];~p;p=next[p]){
            int v=to[p];
            int w=cost[p];
            if(dp[v][st[v]|state]>dp[u][state]+w){
                dp[v][st[v]|state]=dp[u][state]+w;
                if(st[v]|state!=state||vis[v][state])continue;
                vis[v][state]=1;
                Q.push(v);
            }
        }
    }
}
void STMA(){
    stma_init();
    for(int j=1;j<all;j++){
        rep(i,n){
           if(st[i]&&(st[i]&j)==0)continue;
           for(int sub=(j-1)&j;sub;sub=(sub-1)&j){
               int x=st[i]|sub,y=st[i]|(j-sub);
               dp[i][j]=min(dp[i][j],dp[i][x]+dp[i][y]);
           }
           if(dp[i][j]<INF){
               Q.push(i);
               vis[i][j]=true;
           }
        }
        spfa(j);
    }
}
/*
void spfa(){
    while(!Q.empty()){
        int j=Q.front()/1200;
        int i=Q.front()%1200;
        Q.pop();
        vis[j][i]=0;
        for(int p=head[j];~p;p=next[p]){
            int v=to[p],w=cost[p];
            int nxt=i|st[v];
            if(dp[j][i]+w<dp[v][nxt]){
                dp[v][nxt]=dp[j][i]+w;
                if(nxt==i&&!vis[v][nxt]){
                    vis[v][nxt]=1;
                    Q.push(v*1200+nxt);
                }
            }
        }
    }
}
void STMA(){
    stma_init();
    rep(i,all){
        rep(j,n){
            for(int t=(i-1)&i;t;t=(t-1)&i){
                dp[j][i]=min(dp[j][i],dp[j][t|st[j]]+dp[j][(i-t)|st[j]]);
            }
            if(dp[j][i]<INF){
                Q.push(j*1200+i);
                vis[j][i]=1;
            }
        }
        spfa();
    }
}*/
bool check(int s){
    int cnt=0;
    rep(i,k){
        if(s&(1<<i))cnt++;
        if(s&(1<<(k+i)))cnt--;
    }
    return cnt==0;
}
void bug(){
    puts("bug");
    pf("%d\n",all);
    rep(i,all)pf("%d ",dpans[i]);
}
void solve(){
   STMA();//模板,求出来的是一颗树

   //因为这道题的解可能是森林,所以要对求出来的东东再进行dp
   rep(i,all){
      dpans[i]=INF;
      rep(j,n)dpans[i]=min(dpans[i],dp[j][i]);
   }
   for(int i=1;i<all;i++){
       if(check(i)){
           for(int j=(i-1)&i;j;j=(j-1)&i){
               if(check(j))dpans[i]=min(dpans[i],dpans[j]+dpans[i-j]);
           }
       }
   }
   if(dpans[all-1]<INF)pf("%d\n",dpans[all-1]);
   else puts("No solution");
}
int main(){
    int T;sf("%d",&T);
    while(T--){
        init();
        input();
        solve();
    }
    return 0;
}
时间: 2024-10-03 04:28:04

斯坦纳树模板的相关文章

HDU 4085 斯坦纳树模板题

Dig The Wells Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 971    Accepted Submission(s): 416 Problem Description You may all know the famous story "Three monks". Recently they find som

【模板】斯坦纳树

链接: #include <stdio.h> int main() { puts("转载请注明出处[辗转山河弋流歌 by 空灰冰魂]谢谢"); puts("网址:blog.csdn.net/vmurder/article/details/46499973"); } 题目: 斯坦纳树 Time Limit: 1 Sec Memory Limit: 128 MB Description 现在有一个n*m的矩阵,某些元素为0,剩下的元素大于0. 现在你要选择一

BZOJ 2595 [Wc2008]游览计划 ——斯坦纳树

[题目分析] 斯坦纳树=子集DP+SPFA? 用来学习斯坦纳树的模板. 大概就是用二进制来表示树包含的点,然后用跟几点表示树的形态. 更新分为两种,一种是合并两个子集,一种是换根,换根用SPFA迭代即可. [代码] #include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <set> #include <map> #include

【BZOJ2595】【Wc2008】游览计划、斯坦纳树

题解:斯坦纳树,实现神马的在代码里面有还看得过去的注释. 代码: #include <queue> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define N 15 #define inf 0x3f3f3f3f using namespace std; const int dx[]={0,0,1,-1}; const int dy[

BZOJ 2595: [Wc2008]游览计划 [DP 状压 斯坦纳树 spfa]【学习笔记】

传送门 题意:略 论文 <SPFA算法的优化及应用> http://www.cnblogs.com/lazycal/p/bzoj-2595.html 本题的核心就是求斯坦纳树: Steiner Tree: Given an undirected graph with non-negative edge weights and a subset of vertices, usually referred to as terminals, the Steiner tree problem in g

[WC2008]游览计划 「斯坦那树模板」

斯坦那树 百度释义 斯坦纳树问题是组合优化问题,与最小生成树相似,是最短网络的一种.最小生成树是在给定的点集和边中寻求最短网络使所有点连通.而最小斯坦纳树允许在给定点外增加额外的点,使生成的最短网络开销最小. 即最小斯坦那树即为并非选择所有的结点,而是选择一部分结点,为保证它们连通,且求解最小开销 题解 斯坦那树模板 发现直接表示点的存在性没有意义 设函数 \(f[i][state]\) 表示:对于点 \(i\),其它结点与其连通情况 那么有两种转移 其一.由其子集转移 \[f[i][state

FJoi2017 1月20日模拟赛 直线斯坦纳树(暴力+最小生成树+骗分+人工构造+随机乱搞)

[题目描述] 给定二维平面上n个整点,求该图的一个直线斯坦纳树,使得树的边长度总和尽量小. 直线斯坦纳树:使所有给定的点连通的树,所有边必须平行于坐标轴,允许在给定点外增加额外的中间节点. 如下图所示为两种直线斯坦纳树的生成方案,蓝色点为给定的点,红色点为中间节点. [输入格式] 第一行一个整数n,表示点数. 以下n行,每行两个整数表示点的x,y坐标. [输出格式] 第一行一个整数m,表示中间节点的个数. 必须满足m <= 10 * n 以下m行,每行2个整数表示中间节点的坐标. 以下n+m-1

BZOJ 3205 [Apio2013]机器人 ——斯坦纳树

腊鸡题目,实在卡不过去. (改了一下午) 就是裸的斯坦纳树的题目,一方面合并子集,另一方面SPFA迭代求解. 优化了许多地方,甚至基数排序都写了. 还是T到死,不打算改了,就这样吧 #include <map> #include <cmath> #include <queue> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm

【Foreign】修路 [斯坦纳树]

修路 Time Limit: 20 Sec  Memory Limit: 256 MB Description Input Output 仅一行一个整数表示答案. Sample Input 5 5 2 1 3 4 3 5 2 2 3 1 3 4 4 2 4 3 Sample Output 9 HINT Main idea 给定若干对点,选择若干边,询问满足每对点都连通的最小代价. Source 发现 d 非常小,所以我们显然可以使用斯坦纳树来求解. 斯坦纳树是用来解决这种问题的:给定若干关键点,