ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

POJ1639 Picnic Planning (限制入度最小生成树)

2022-07-18 12:01:24  阅读:165  来源: 互联网

标签:mini Picnic int 32 入度 tree fx Planning fy


节点1是有度数限制的,把节点1去掉,就会形成若干个连通块,在每个连通块内部求最小生成树(prim算法实现),并求出每个连通块与1相连的最短的边,这样形成了初始状态的生成树。

假设(1,x)这条边没在生成树中,如果在生成树中从1到x的路径中的最大边权大于(1,x),考虑加上(1,x),去掉这条最大边权的边,答案就更加优秀了,若干次重复这样的操作,直到达到度数限制,就可以得到最优解。

记录最大边权的思路基于DP,回溯打标记。

完成一次拓展后,加入了(1,x)这条边,修改x的f[ ],fx[ ],fy[ ],给1打上标记,从x开始DP,因为只是修改了x所在的连通块,没有必要再从1遍历一次。(可以画图理解一下)。

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 int n,m,s,deg,ans;
  4 int a[32][32],d[32],conn[32];
  5 bool v[32],c[32];
  6 int tree[32][32];
  7 int ver[32],p;
  8 int f[32],fx[32],fy[32];//1-x的路径最大边权是f[x],两个端点是fx[x],fy[x]
  9 
 10 void read(){
 11     map<string,int> h;
 12     cin>>m;
 13     h["Park"]=1;n=1;
 14     memset(a,0x3f,sizeof(a));
 15     for(int i=1;i<=m;i++){
 16         int x,y,z;
 17         char sx[12],sy[12];
 18         scanf("%s%s%d",sx,sy,&z);
 19         if(!h[sx]) h[sx]=++n;
 20         if(!h[sy]) h[sy]=++n;
 21         x=h[sx],y=h[sy];
 22         a[x][y]=min(a[x][y],z);
 23         a[y][x]=min(a[y][x],z);
 24     }
 25     cin>>s;
 26 }
 27 
 28 void prim(int root){
 29     d[root]=0;
 30     for(int i=1;i<=p;i++){
 31         int x=0;
 32         for(int j=1;j<=p;j++)
 33             if(!v[ver[j]]&&(x==0||d[ver[j]]<d[x])) x=ver[j];
 34         v[x]=true;
 35         for(int j=1;j<=p;j++){
 36             int y=ver[j];
 37             if(!v[y]&&d[y]>a[x][y])
 38                 d[y]=a[x][y],conn[y]=x;
 39         }
 40     }//prim算法模板
 41     int closest=root;
 42     for(int i=1;i<=p;i++){
 43         int x=ver[i];
 44         if(x==root) continue;
 45         ans+=d[x];
 46         tree[conn[x]][x]=tree[x][conn[x]]=d[x];
 47         if(a[1][x]<a[1][closest]) closest=x;//记录连通块中和1相连最短的边 
 48     } 
 49     deg++;
 50     ans+=a[1][closest];
 51     tree[1][closest]=tree[closest][1]=a[1][closest];
 52 }
 53 
 54 void dfs(int x){
 55     ver[++p]=x;
 56     c[x]=true;
 57     for(int y=2;y<=n;y++)
 58         if(a[x][y]!=0x3f3f3f3f&&!c[y]) dfs(y);
 59 }
 60 
 61 void prim_for_all_comp(){
 62     memset(d,0x3f,sizeof(d));
 63     memset(v,0,sizeof(v));
 64     memset(tree,0x3f,sizeof(tree));
 65     c[1]=true;
 66     for(int i=2;i<=n;i++){
 67         if(!c[i]){
 68             p=0;
 69             dfs(i);
 70             prim(i);
 71         }
 72     }
 73 }
 74 
 75 void dp(int x){
 76     v[x]=true;
 77     for(int y=2;y<=n;y++){
 78         if(tree[x][y]!=0x3f3f3f3f&&!v[y]){
 79             if(f[x]>tree[x][y]){
 80                 f[y]=f[x];
 81                 fx[y]=fx[x],fy[y]=fy[x];
 82             }else{
 83                 f[y]=tree[x][y];
 84                 fx[y]=x,fy[y]=y;
 85             }
 86             dp(y);
 87         }
 88     }
 89     v[x]=false;//回溯 
 90 }
 91 
 92 bool solve(){
 93     int min_val=1<<30,mini;
 94     for(int i=2;i<=n;i++){//枚举从1出发的非树边(1,i),看加哪一条
 95         if(tree[1][i]!=0x3f3f3f3f||a[1][i]==0x3f3f3f3f) continue;
 96         //加入非树边(1,i),删去树边(fx[i],fy[i])
 97         if(a[1][i]-tree[fx[i]][fy[i]]<min_val){
 98             min_val=a[1][i]-tree[fx[i]][fy[i]];
 99             mini=i;
100         }
101     }
102     if(min_val>=0) return false;
103     ans+=min_val;
104     tree[1][mini]=tree[mini][1]=a[1][mini];
105     tree[fx[mini]][fy[mini]]=tree[fy[mini]][fx[mini]]=0x3f3f3f3f;//删去原边,增加新边
106     f[mini]=a[1][mini];
107     fx[mini]=1,fy[mini]=mini;
108     v[1]=true;
109     dp(mini);//重新计算以mini为根的子树的dp状态 
110     return true; 
111 }
112 
113 int main(){
114     read();
115     prim_for_all_comp();
116     memset(v,0,sizeof(v));
117     dp(1);
118     while(deg<s){
119         if(!solve()) break;
120         deg++;
121     }
122     printf("Total miles driven: ");
123     cout<<ans<<endl;
124 }

 

标签:mini,Picnic,int,32,入度,tree,fx,Planning,fy
来源: https://www.cnblogs.com/yhxnoerror/p/16489928.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有