蓝书(算法竞赛进阶指南)刷题记录——POJ1639 Picnic Planning(度限制最小生成树)

版权声明:转载请注明原出处啦QAQ(虽然应该也没人转载): https://blog.csdn.net/hzk_cpp/article/details/83111663

题目:POJ1639.

题目大意:给定一张无向图,求这张无向图的最小生成树,其中这棵最小生成树满足节点1的度小于等于s.

我们对于一张图,先将点1去掉,剩下的联通块内的的最小生成树都求出,然后我们在枚举与1关联的边,将所有联通块与1只连一条最小的边,这样我们就求出了一棵最小T度生成树,其中T等于去掉点1后联通块数量.

我们求出最小T度生成树之后,我们再求最小S度生成树.注意,我们下面所说的最小k度指的是点1的度必须为k.

我们考虑最小k度生成树如何转移到最小k+1度生成树.我们考虑枚举一条与1相连但没有被选入最小生成树的边(1,x),然后我们会发现出现了一个环,其中这个环由一条非树边(1,x)和一条树链(x,1)组成.

我们考虑暴力枚举树链上的每一条,找到边权最大的边,看是否最优即可.

但是这样做的时间复杂度最坏情况下为O(ElogE+sVE),我们考虑更加优秀的做法.

我们发现这个算法的瓶颈在于枚举到一个点时需要在枚举至多O(E)级别条边,那么我们是否可以考虑优化这个过程.

我们考虑每一次转移都先进行一个树形DP,这个DP的状态f[x]表示树上的链(1,x)上的最大边权,并且记录这条边的编号,方便删除.

那么时间复杂度为O(ElogE+s(V+E)).

由于时限宽松,这里写了邻接矩阵写法的dfs,若要达到上述那个更优的时间复杂度,需要写一个双向链表形式的邻接表.

代码如下:

#include<iostream>
#include<cstdio>
#include<map>
#include<algorithm>
  using namespace std;
#define Abigail inline void
#define mt map<string,int>::iterator
typedef long long LL;
const int N=300,INF=(1<<29)-1;
map<string,int>q;
struct graph_side{
  int x,y,v;
  bool operator < (const graph_side p)const{return v<p.v;}
}e[N+9];
int m,n,s,ans;
int fa[N+9];
int tr[N+9][N+9],g[N+9][N+9];
struct node{
  int x,y,v;
}dp[N+9];
int get(int u){return u^fa[u]?fa[u]=get(fa[u]):u;}
int kruskal(){
  int cnt=0;
  for (int i=1;i<=n;i++) fa[i]=i;
  sort(e+1,e+1+m);
  for (int i=1;i<=m;i++){
    if (e[i].x==1||e[i].y==1) continue;
    int grx=get(e[i].x),gry=get(e[i].y);
    if (grx==gry) continue;
    fa[grx]=gry;
    tr[e[i].x][e[i].y]=tr[e[i].y][e[i].x]=1;
    ans+=e[i].v;
  }
  for (int i=1;i<=m;i++){
    if (e[i].x^1&&e[i].y^1) continue;
    int grx=get(e[i].x),gry=get(e[i].y);
    if (grx==gry) continue;
    cnt++;
    fa[grx]=gry;
    tr[e[i].x][e[i].y]=tr[e[i].y][e[i].x]=1;
    ans+=e[i].v;
  }
  return cnt;
}
void dfs(int k,int fa){
  for (int i=2;i<=n;i++)
    if (i^fa&&tr[k][i]){
      dp[i].v=g[k][i];dp[i].x=k;dp[i].y=i;
      if (dp[i].v<dp[k].v) dp[i]=dp[k];
      dfs(i,k);
    }
}
Abigail into(){
  string s1,s2;
  mt it;
  int v;
  for (int i=1;i<=N;i++)
    for (int j=1;j<=N;j++)
      g[i][j]=INF;
  scanf("%d",&m);
  q.insert(make_pair("Park",n=1));
  for (int i=1;i<=m;i++){
    cin>>s1>>s2;
    it=q.find(s1);
    if (it==q.end()){
      e[i].x=++n;
      q.insert(make_pair(s1,n));
    }else e[i].x=q[s1];
    it=q.find(s2);
    if (it==q.end()){
      e[i].y=++n;
      q.insert(make_pair(s2,n));
    }else e[i].y=q[s2];
    scanf("%d",&e[i].v);
    g[e[i].x][e[i].y]=g[e[i].y][e[i].x]=min(e[i].v,g[e[i].x][e[i].y]);
  }
  scanf("%d",&s);
}
Abigail work(){
  int cnt=kruskal();
  for (int i=cnt+1;i<=s;i++){
    dfs(1,0);
    int minn=INF,v=0;
    for (int j=2;j<=n;j++)
      if (!tr[1][j]&&minn>g[1][j]-dp[j].v) minn=g[1][j]-dp[j].v,v=j;
    if (minn>=0||!v) break;
    ans+=minn;
    tr[1][v]=tr[v][1]=1;
    tr[dp[v].x][dp[v].y]=tr[dp[v].y][dp[v].x]=0;
  }
}
Abigail outo(){
  printf("Total miles driven: %d\n",ans);
}
int main(){
  int T=1,_=0;
  while (T--){
    into();
    work();
    outo();
  }
  return 0>_<0;
}

猜你喜欢

转载自blog.csdn.net/hzk_cpp/article/details/83111663
今日推荐