Joining Capitals (斯坦纳树)
作者:互联网
最小斯坦纳树:
- 目的:将目标点连接起来形成连通,可以通过一些其他点作为桥梁来构造。(花费值最小)
- 其结果一定是一个树
- 利用dp【i】【s】2种状态转移。
- 1 利用根节点进行最短路的转移
- 2 利用利用 根节点相同不同的子叶节点进行转移。
- 利用的知识点: 压状dp+最短路
- 小知识点: 如何枚举压状dp的每一个子节点。sur=s&(sur-1)
- 1<<n的优先级很低,要打括号。在最后弄ans的时候一定要特别注意
- 斯坦纳深林,就是分别把每一个斯坦纳树求出来,再利用压状dp进行背包更新就行拉。
基本模板:
【模板】最小斯坦纳树 (洛谷)
#include <bits/stdc++.h> using namespace std; #define ri register int #define M 105 template <class G> void read(G &x) { x=0;int f=0;char ch=getchar(); while(ch<'0'||ch>'9'){f|=ch=='-';ch=getchar();} while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} x=f?-x:x; return ; } struct dian{ int val,to; }; vector <dian> p[M]; int n,m,T; int dp[M][1<<11]; int k[M]; int dis[M]; struct cmp { bool operator ()(const int a,const int b)const { return dis[a]>dis[b]; } }; int vis[M]; void dj(int s) { memset(dis,0x3f,sizeof(dis)); memset(vis,0,sizeof(vis)); priority_queue<int,vector<int>,cmp> q; for(ri i=1;i<=n;i++) { if(dp[i][s]<dis[i]) { dis[i]=dp[i][s]; q.push(i); } } while(!q.empty()) { while(!q.empty()&&vis[q.top()]) q.pop(); int a=q.top(); if(q.empty()) break; vis[a]=1; for(ri i=0;i<p[a].size();i++) { int b=p[a][i].to; if(dis[b]>dis[a]+p[a][i].val) { dis[b]=dis[a]+p[a][i].val; q.push(b); } } } for(ri i=1;i<=n;i++) { dp[i][s]=dis[i]; // printf("%d\n",dis[i]); } } int main(){ read(n);read(m);read(T); for(ri i=1;i<=m;i++) { dian t;int a,b,c; read(a);read(b);read(t.val); t.to=b; p[a].push_back(t); t.to=a; p[b].push_back(t); } memset(dp,0x3f,sizeof(dp)); for(ri i=1;i<=T;i++) { read(k[i]); dp[k[i]][1<<(i-1)]=0; } for(ri s=1;s<(1<<T);s++) { for(ri i=1;i<=n;i++) { for(ri sur=s&(s-1);sur;sur=s&(sur-1)) { dp[i][s]=min(dp[i][s],dp[i][sur]+dp[i][s^sur]); } } dj(s); } int ans=dp[0][0];//printf("%d\n",ans); for(ri i=1;i<=n;i++) ans=min(ans,dp[i][(1<<(T))-1]); printf("%d",ans); return 0; }View Code
A far far away kingdom has NN cities, among which KK are capitals. King Richard wants to build transmission lines, each one directly connecting two cities. Also, there needs to be a path, i.e. a sequence of transmission lines, between any pair of capitals. Each transmission line has an associated cost, which is the Euclidean distance between the two cities that the transmission line connects. As the king is greedy, he wishes that the transmission lines are set up so that the total cost (sum of the costs for each line) is kept as small as possible. The figure A shows an example of a kingdom with N = 10N=10 cities and K = 4K=4 capitals. The Chief Engineer reported to the king the solution shown in figure B. Such solution, in fact, minimizes the total cost. But the king didn't like to see a capital with more than one transmission line. He then determined a new restriction: a capital can be connected to only one other city. That way, after working a lot, Chief Engineer presented the new solution, illustrated in figure C. He's just not so sure if this is the optimal solution, so he needs your help. Given the coordinates of the cities, your program should compute the smallest total cost to build transmission lines so that every pair of capitals is connected by a sequence of transmission lines and every capital is directly connected to only one city. Input The first line of the input contains two integers N, KN,K (4 \leq N \leq 1004≤N≤100; 3 \leq K < \min(10, N))3≤K<min(10,N)), indicating respectively the number of cities and the number of capitals. The following NN lines contain two integers XX and YY each (−1000 \leq X, Y \leq 1000−1000≤X,Y≤1000), representing the coordinates of a city. The KK first cities are the capitals. There are no two cities with the same coordinates. Output Print a line containing a real number, with 5 decimal places, indicating the smallest total cost to build transmission lines, according to the restrictions above.View problem
思路:
- 由于每一个目标节点只能有一个边,所以对每一个目标节点只连接不是目标节点的节点。
- 在最短路的时候,要对目标节点更新的时候就跳过,只让他去跟新别人,不能让别人更新他
#include <bits/stdc++.h> using namespace std; #define ri register int #define M 105 template <class G> void read(G &x) { x=0;int f=0;char ch=getchar(); while(ch<'0'||ch>'9'){f|=ch=='-';ch=getchar();} while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} x=f?-x:x; return ; } struct dian{ int to;double val; }; vector <dian> p[M]; int n,m,T; double dp[M][(1<<11)+5]; double dis[M]; struct cmp { bool operator ()(const int a,const int b)const { return dis[a]>dis[b]; } }; int vis[M]; void dj(int s) { for(ri i=1;i<=n;i++) dis[i]=1e9; memset(vis,0,sizeof(vis)); priority_queue<int,vector<int>,cmp> q; for(ri i=1;i<=n;i++) { if(dp[i][s]<dis[i]) { dis[i]=dp[i][s]; q.push(i); } } while(!q.empty()) { while(!q.empty()&&vis[q.top()]) q.pop(); int a=q.top(); if(q.empty()) break; vis[a]=1; for(ri i=0;i<p[a].size();i++) { int b=p[a][i].to; if(b<=T) continue; if(dis[b]>dis[a]+p[a][i].val) { dis[b]=dis[a]+p[a][i].val; q.push(b); } } } for(ri i=1;i<=n;i++) { dp[i][s]=dis[i]; // printf("%d\n",dis[i]); } } struct dn{ double x,y; }node[M]; double get(int a,int b) { return sqrt((node[a].x-node[b].x)*(node[a].x-node[b].x)+(node[a].y-node[b].y)*(node[a].y-node[b].y)); } int main(){ read(n);read(T); for(ri i=1;i<=n;i++) { cin>>node[i].x>>node[i].y; } for(ri i=1;i<=T;i++) { for(ri j=T+1;j<=n;j++) { double a=get(i,j); dian t; t.to=j;t.val=a; p[i].push_back(t); t.to=i; p[j].push_back(t); } } for(ri i=T+1;i<=n;i++) { for(ri j=T+1;j<=n;j++) { if(i==j) continue; double a=get(i,j); dian t; t.to=j;t.val=a; p[i].push_back(t); t.to=i; p[j].push_back(t); } } for(ri i=0;i<=n;i++) for(ri s=0;s<=(1<<T);s++) dp[i][s]=1e9; for(ri i=1;i<=T;i++) { dp[i][1<<(i-1)]=0; } for(ri s=1;s<(1<<T);s++) { for(ri i=1;i<=n;i++) { for(ri sur=s&(s-1);sur;sur=s&(sur-1)) { dp[i][s]=min(dp[i][s],dp[i][sur]+dp[i][s^sur]); } } dj(s); } double ans=dp[0][0]; for(ri i=1;i<=n;i++) ans=min(ans,dp[i][(1<<(T))-1]);// printf("%0.5lf",ans); return 0; }View Code
后记:
- 在调用不是void 函数的时候 一定要返回,本题就是 get函数没有写 return,前面小数据的时候没有写return居然也可以自动给我返回了,但是在大数据就不行了!!
标签:ch,int,Capitals,节点,斯坦纳,transmission,ri,dp,Joining 来源: https://www.cnblogs.com/Lamboofhome/p/16195306.html