最小树形图
最小树形图学习笔记
直接上代码吧
#include<bits/stdc++.h>
using namespace std;
const int maxn=109;
const int oo=1000000000;
int n,m,r;
int w[maxn][maxn];
int flag[maxn];
int pre[maxn],vis[maxn];
int Mst(){
int ans=0;
for(;;){
for(int i=1;i<=n;++i){
if(i==r||flag[i])continue;
w[i][i]=oo;pre[i]=i;
for(int j=1;j<=n;++j){
if(flag[j])continue;
if(w[j][i]<w[pre[i]][i])pre[i]=j;
}
if(pre[i]==i)return -1;
}
int beg=0;
for(beg=1;beg<=n;++beg){
if(beg==r||flag[beg])continue;//!!!!!!
int x=beg,cnt=0;
while(x!=r&&pre[x]!=beg&&cnt<=n){
x=pre[x];++cnt;
}
if(x==r||cnt>n)continue;
break;
}
if(beg>n){
for(int i=1;i<=n;++i){
if(i!=r&&!flag[i]){
ans+=w[pre[i]][i];
}
}
return ans;
}
int x=beg;
memset(vis,0,sizeof(vis));
for(;;){
ans+=w[pre[x]][x];x=pre[x];vis[x]=flag[x]=1;
if(x==beg)break;
}
flag[beg]=0;
for(int i=1;i<=n;++i){
if(!vis[i])continue;
for(int j=1;j<=n;++j){
if(vis[j])continue;
if(w[i][j]<w[beg][j])w[beg][j]=w[i][j];
if(w[j][i]!=oo&&w[j][i]-w[pre[i]][i]<w[j][beg]){
w[j][beg]=w[j][i]-w[pre[i]][i];
}
}
}
}
return ans;
}
int main(){
scanf("%d%d%d",&n,&m,&r);
for(int i=1;i<=n;++i){
for(int j=1;j<=n;++j){
w[i][j]=oo;
}
}
while(m--){
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
if(x!=y){
w[x][y]=min(w[x][y],z);
}
}
printf("%d\n",Mst());
return 0;
}
BZOJ 4349 最小树形图
题解:显然是所有的堡垒先都打完一遍,
然后还有需要打的堡垒就用入边权值最小的代价打
求打完一遍的权值和
建立虚点root,向1-n连边
然后再连好读入的边,跑最小树形图就可以了
#include<bits/stdc++.h>
using namespace std;
const int maxn=109;
const int oo=1000000000;
int n,m,root;
double ans=0;
double A[maxn];int B[maxn];
double w[maxn][maxn];
double minedge[maxn];
int flag[maxn];
int vis[maxn],pre[maxn];
double Mst(){
double ret=0;
for(;;){
for(int i=1;i<=n;++i){
if(i==root||flag[i])continue;
w[i][i]=oo;pre[i]=i;
for(int j=1;j<=n;++j){
if(flag[j])continue;
if(w[j][i]<w[pre[i]][i])pre[i]=j;
}
}
int beg;
for(beg=1;beg<=n;++beg){
if(beg==root||flag[beg])continue;
int x=beg,cnt=0;
while(x!=root&&pre[x]!=beg&&cnt<=n){
x=pre[x];++cnt;
}
if(x==root||cnt>n)continue;
break;
}
if(beg>n){
for(int i=1;i<=n;++i){
if(!flag[i]&&i!=root){
ret+=w[pre[i]][i];
}
}
return ret;
}
int x=beg;
memset(vis,0,sizeof(vis));
for(;;){
ret+=w[pre[x]][x];x=pre[x];vis[x]=flag[x]=1;
if(x==beg)break;
}
flag[x]=0;
for(int i=1;i<=n;++i){
if(!vis[i])continue;
for(int j=1;j<=n;++j){
if(vis[j])continue;
if(w[i][j]<w[x][j])w[x][j]=w[i][j];
if(w[j][i]!=oo&&w[j][i]-w[pre[i]][i]<w[j][x])w[j][x]=w[j][i]-w[pre[i]][i];
}
}
}
}
int main(){
// freopen("fuck.in","r",stdin);
scanf("%d",&n);
root=n+1;
for(int i=1;i<=n+1;++i){
for(int j=1;j<=n+1;++j){
w[i][j]=oo;
}
}
for(int i=1;i<=n;++i){
cin>>A[i]>>B[i];
w[root][i]=A[i];
minedge[i]=A[i];
}
scanf("%d",&m);
while(m--){
int x,y;double z;
cin>>x>>y>>z;
if(x!=y){
w[x][y]=min(w[x][y],z);
}
minedge[y]=min(minedge[y],z);
}
n=n+1;
ans+=Mst();
for(int i=1;i<=n;++i)ans+=(B[i]-1)*minedge[i];
printf("%.2f\n",ans);
return 0;
}
致歉:笔者已经意识到这是一篇几乎没有价值的文章,给您的阅读带来不好的体验,并且干扰了您的搜索环境,非常抱歉!