斯坦纳树

#line 5 "FoxTheLinguist.cpp"
#include <bits/stdc++.h>
using namespace std;

int head,tail,n,dl[10001],indl[10001],nxt[10001],len[10001],dis[3501][110],nd[10001],des[10001],cnt;
char st[1000001];

void spfa(int dis[]){
  head=1;tail=0;
  for (int i=0;i<=n*10;i++) dl[++tail]=i,indl[i]=1;
  while (head<=tail){
      for (int p=nd[dl[head]];p!=-1;p=nxt[p])
        if (dis[des[p]]>dis[dl[head]]+len[p]){
          dis[des[p]]=dis[dl[head]]+len[p];
          if (!indl[des[p]]){
            dl[++tail]=des[p];
          indl[des[p]]=1;
        }
      }
    indl[dl[head++]]=0;
  }
}

void Steiner(){
  for (int i=0;i<=n*10;i++) for (int j=0;j<=(1<<(n+1))-1;j++) dis[j][i]=1e9;
  dis[1][0]=0;
  for (int i=1;i<=n;i++) dis[1<<i][i*10]=0;
  for (int mask=1;mask<=(1<<(n+1))-1;mask++){
    for (int j=0;j<=10*n;j++)
      for (int k=(mask-1)&mask;k;k=(k-1)&mask)
        dis[mask][j]=min(dis[mask][j],dis[k][j]+dis[mask-k][j]);

    spfa(dis[mask]);
  }
}

void addedge(int x,int y,int le){
  nxt[++cnt]=nd[x];des[cnt]=y;len[cnt]=le;nd[x]=cnt;
}

class FoxTheLinguist {
    public:
    int minimalHours(int N, vector <string> I) {
      n=N;
      for (int i=0;i<=10*n;i++) nd[i]=-1;
      for (int i=1;i<=n;i++) addedge((i-1)*10+1,0,0);
      for (int i=1;i<=n;i++)
        for (int j=10;j>2;j--)
          addedge((i-1)*10+j-1,(i-1)*10+j,0);
      cnt=-1;
      for (int i=0;i<I.size();i++)
        for (int j=0;j<I[i].size();j++)
          st[++cnt]=I[i][j];

      int po=0;
      while (st[po]>=‘A‘&&st[po]<=‘Z‘){
          int poa=(st[po]-‘A‘)*10+st[po+1]-‘0‘+1,pob=(st[po+4]-‘A‘)*10+st[po+5]-‘0‘+1,num=(st[po+7]-‘0‘)*1000+(st[po+8]-‘0‘)*100+(st[po+9]-‘0‘)*10+(st[po+10]-‘0‘);
          addedge(pob,poa,num);
          po+=12;
      }

      Steiner();

      if (dis[(1<<(n+1))-1][0]==1e9) return(-1);else return(dis[(1<<(n+1))-1][0]);
    }
    
时间: 2024-10-07 21:35:28

斯坦纳树的相关文章

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

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

【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 非常小,所以我们显然可以使用斯坦纳树来求解. 斯坦纳树是用来解决这种问题的:给定若干关键点,

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

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

HDU 4085 斯坦纳树

题目大意: 给定无向图,让前k个点都能到达后k个点(保护地)中的一个,而且前k个点每个需要占据后k个中的一个,相互不冲突 找到实现这个条件达到的选择边的最小总权值 这里很容易看出,最后选到的边不保证整个图是联通的 我们只要计算出每一个连通的最小情况,最后跑一遍dfs就能计算出答案了 那么用dp[i][j]表示 i 点为根得到联通状态为 j 的情况需要选到的边的最小总权值 这个用斯坦纳树的思想就可以做到的 对于每一个状态,都用spfa跑一遍得到最优解 dp[i][j] = min(dp[i][j]

【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[

斯坦纳树模板

屌炸天阿什么东西都有 丢 //斯坦纳树模板 让k个点联通的最小生成树 复杂度 n*3^k #include<iostream> #include<cstring> #include<set> #include<map> #include<cmath> #include<stack> #include<queue> #include<deque> #include<list> #include<

HDU 4085 Peach Blossom Spring 记忆化搜索枚举子集 斯坦纳树

题目链接:点击打开链接 题意: 第一行输入n个点 m条可修建的无向边 k个人 下面给出修建的边和修建该边的花费. 开始时k个人在1-k的每个点上(一个点各一人) 目标:从m条给定边中修建部分边使得花费和最小 让k个人移动到 [n-k+1, n] 后面的k个点上(每个点放一个人). 思路: 首先就是一道斯坦纳树,还是先求一个dp数组(求解方法:点击打开链接) dp[i][j] 表示以i为根 ,j为8个点中是否在 i 的子树里 时的最小花费. 现在的问题就是如何求答案. 因为一个人到他的目标点这条路

【BZOJ 2595】2595: [Wc2008]游览计划 (状压DP+spfa,斯坦纳树?)

2595: [Wc2008]游览计划 Time Limit: 10 Sec  Memory Limit: 256 MBSec  Special JudgeSubmit: 1572  Solved: 739 Description Input 第一行有两个整数,N和 M,描述方块的数目. 接下来 N行, 每行有 M 个非负整数, 如果该整数为 0, 则该方块为一个景点:否则表示控制该方块至少需要的志愿者数目. 相邻的整数用 (若干个) 空格隔开,行首行末也可能有多余的空格. Output 由 N