POJ1639 Picnic Planning 限定度数的最小生成树

该博客探讨了一种特殊的最小生成树问题,其中涉及一个特定的节点(park)具有限制的度数。博主首先介绍了如何在排除park节点的情况下找到各连通块的最小生成树,然后通过染色和边的标记来处理park节点。在连接park与其他连通块后,博主使用BFS寻找可能降低总成本的环,并调整边以优化结果。最终,博主提供了AC代码实现这一算法,用于解决这类问题。
摘要由CSDN通过智能技术生成

题意:

求满足一个点限定度数情况下的最小生成树。

题解:

这题写的是真的麻烦。不考虑限制度数的点park,将剩下几个连通块求出最小生成树,prime一边染色一边最小生成树即可,过程中使用的边进行标记。将park先连上各个连通块最短的边,此时的生成树并不是最优的。此时只有park剩下的边可能对减小结果,因此判断park剩下的边能不能减小贡献就行。对一个树,加上一个边一定会形成环。BFS出这个环,找到最大的边,减去加上的边就是贡献。跑到park的度满了或者加边没有贡献为止。

AC代码:

#include <cstdio>
#include <iostream>
#include <vector>
#include <string>
#include <queue>
#include <algorithm>
#include <cmath>
#include <set>
#include <map>
#include <iomanip>
#include <cstdlib>
#include <stack>
#include <cstring>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define repp(i,a,b) for(int i=(a);i<(b);i++)
#define lep(i,a,b) for(int i=(a);i>=(b);i--) 
#define lepp(i,a,b) for(int i=(a);i>(b);i--)
#define pii pair<int,int>
#define pll pair<long long,long long>
#define mp make_pair
#define pb push_back 
#define fi first
#define se second
#define All(x) x.begin(),x.end() 
#define ms(a,b) memset(a,b,sizeof(a)) 
#define INF 0x3f3f3f3f
#define INFF 0x3f3f3f3f3f3f3f3f
#define multi int T;scanf("%d",&T);while(T--) 
using namespace std;
typedef long long ll;
typedef double db;
const int N=20+5;
const int mod=1e9+7;
const db eps=1e-6;                                                                            
const db pi=acos(-1.0);
int n,park,c[N],s,cnt,dis[N];
map<string,int>num;
int road[N][N],used[N][N],to[N];
struct edge{
    int u,v,w;
    bool operator < (const edge &A) const{
        return w<A.w;
    }
};
int bfs(int x,int &u,int &v){
    int pre[N];
    ms(pre,0);
    pre[x]=park;
    queue<int>q;
    q.push(x);
    while(q.size()){
        int cur=q.front();
        q.pop();
        if(cur==park) break;
        rep(i,1,cnt)
            if(used[cur][i]==1&&pre[i]==0){
                pre[i]=cur;
                q.push(i);
            }
    }
    int w=0,cur=park;
    while(pre[cur]!=park){
        if(w<road[cur][pre[cur]]){
            w=road[cur][pre[cur]];
            u=cur,v=pre[cur];
        }
        cur=pre[cur];
    }
    return w;
}
int main(){
    #ifndef ONLINE_JUDGE
    freopen("D:\\work\\data.in","r",stdin);
    #endif
    int minn[N],n,bef[N];
    cin>>n;
    cnt=0;
    ms(road,INF);
    ms(dis,INF);
    ms(bef,0);
    rep(i,1,n){
        string s1,s2;
        int w;
        cin>>s1>>s2>>w;
        if(num.find(s1)==num.end()) num[s1]=++cnt;
        if(num.find(s2)==num.end()) num[s2]=++cnt;
        road[num[s1]][num[s2]]=road[num[s2]][num[s1]]=w;
        if(s1=="Park") park=num[s1];
        if(s2=="Park") park=num[s2];
    }
    int color=0,ans=0;
    c[park]=++color;
    rep(i,1,cnt){
        if(c[i]) continue;
        ++color;
        priority_queue<pii>q;
        q.push(mp(0,i));
        dis[i]=0;
        while(q.size()){
            int idx=q.top().second,w=-q.top().first;
            q.pop();
            if(c[idx]) continue;
            c[idx]=color;
            if(bef[idx]){
                used[bef[idx]][idx]=1;
                used[idx][bef[idx]]=1;
            }
            ans+=w;
            // q.pop();pop要在push之前,要不然对于最小生成树这种并不是单调的,可能pop掉刚push的
            rep(j,1,cnt){
                if(c[j]) continue;
                if(dis[j]>road[idx][j]){
                    dis[j]=road[idx][j];
                    bef[j]=idx;
                    q.push({-dis[j],j});
                }  
            }
        }
    }
    ms(minn,INF);
    minn[c[park]]=0;
    rep(i,1,cnt){
        if(minn[c[i]]>road[park][i]){
            minn[c[i]]=road[park][i];
            to[c[i]]=i;
        }
    }
    rep(i,2,color){
        ans+=minn[i];
        used[park][to[i]]=used[to[i]][park]=1;
    }
    cin>>s;
    rep(i,1,s-color+1){
        edge e,maxn;
        int pos;
        maxn.w=0;
        rep(j,1,cnt){
            if(used[park][j]==1||road[park][j]==INF) continue;
            e.w=bfs(j,e.u,e.v)-road[park][j];
            if(e.w>maxn.w){maxn=e,pos=j;} 
        }
        if(maxn.w<=0) break;
        else{
            ans-=maxn.w;
            used[park][pos]=used[pos][park]=1;
            used[maxn.u][maxn.v]=used[maxn.v][maxn.u]=0;
        }
    }
    cout<<"Total miles driven: "<<ans<<endl;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值