题解:AT_abc395_g [ABC395G] Minimum Steiner Tree 2
include13_fAKe · · 题解
很厉害的题,硬控我一天,让我又补完一场 ABC。
前置知识:P6192 【模板】最小斯坦纳树
因为是要加入两个点,所以考虑把第一个点放入集合,作为第
接下来就转化成了 ABC364G 的那个问题,考虑
本题 Floyd 转移最短路是没有问题的,建议直接使用 Floyd。
朴素最小斯坦纳树的时间复杂度为
#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read(){
int a=0,b=1;
char c=getchar();
while(!isdigit(c)){
if(c=='-') b=-1;
c=getchar();
}
while(isdigit(c)){
a=(a<<1)+(a<<3)+(c-'0');
c=getchar();
}
return a*b;
}
inline void write(int x){
if(x<0) putchar('-'),x=-x;
if(x>=10) write(x/10);
putchar(x%10+48);
}
inline void write1(int x){
write(x),putchar(' ');
}
inline void write2(int x){
write(x),putchar('\n');
}
const int N=107;
const int M=2007;
int n,k,q;
int C[N][N];
int dp[N][M][N]; //dp[k+1][S][j] 选取的 k+1 个点为 k+1 集合为 S 目前到了 j
int key[12]; //注意 key 的最后一位会动态修改
int pow3[12];
void init(){
pow3[0]=1;
for(int i=1;i<=10;i++){
pow3[i]=pow3[i-1]*3;
}
}
signed main(){
init();
n=read(),k=read();
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
C[i][j]=read();
}
}
for(int k_=1;k_<=n;k_++){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
C[i][j]=min(C[i][j],C[i][k_]+C[k_][j]);
}
}
}
for(int i=1;i<=k;i++){
key[i]=i;
}
memset(dp,0x3f,sizeof(dp));
for(int i=1;i<=n;i++){
dp[i][1<<k][i]=0;
}
for(int new_=k+1;new_<=n;new_++){
//new_ 是第 k+1 个点
key[k+1]=new_;
//然后跑一般的 minimum steiner tree 即可
for(int i=1;i<=k+1;i++){
dp[new_][1<<(i-1)][key[i]]=0; //代表这个时候先处理为 0
// cout<<'#'<<new_<<' '<<(1<<(i-1))<<' '<<key[i]<<' '<<0<<endl;
}
for(int i=1;i<pow3[k+1];i++){
int now=i,a=0,b=0; //分成 a b 两个子集
for(int j=0;j<k+1;j++){
int x=now%3;
if(x==1) a+=(1<<j);
if(x==2) b+=(1<<j);
now/=3;
}
for(int j=1;j<=n;j++){
dp[new_][a|b][j]=min(dp[new_][a|b][j],dp[new_][a][j]+dp[new_][b][j]);
// cout<<(a|b)<<' '<<new_<<' '<<j<<' '<<dp[new_][a|b][j]<<endl;
}
if(a==0){
for(int j=1;j<=n;j++){
//转移的都是 dp[new_][a|b][j]
for(int k_=1;k_<=n;k_++){
dp[new_][a|b][j]=min(dp[new_][a|b][j],dp[new_][a|b][k_]+C[k_][j]);
// cout<<(a|b)<<' '<<new_<<' '<<j<<' '<<dp[new_][a|b][j]<<endl;
}
}
}
}
}
q=read();
while(q--){
int x=read(),y=read();
write2(dp[x][(1<<(k+1))-1][y]);
}
putchar('\n');
return 0;
}//天青青等烟雨 而我在等你
其实本题我一直有一种错误思路,就是设