题目:http://poj.org/problem?id=1639

对根的度数有限制的最小生成树;

先忽略根,跑最小生成树,得到几个连通块,再一一与根连上;

然后在限制内用根连出去的边来使生成树更小,这需要枚举边以及用dp维护树上边的dfs序之前最大的一个;

此题用邻接矩阵比较方便。

改了一晚上,终于发现是混淆了n和cnt,cnt才是点数。

邻接表失败版:

#include<iostream>
#include<cstdio>
#include<map>
#include<cstring>
#include<algorithm>
using namespace std;
int n,m,head[],ct=,cnt,ed,fa[],cost,reg;
char s1[],s2[];
map<string,int>mp;
struct N{
int to,next,w;
N(int t=,int n=,int ww=):to(t),next(n),w(ww) {}
}edge[],e[];
struct NN{
int v,bh;
}dp[];
bool use[],use2[],lk[],vis[];
bool cmp(N x,N y){return x.w<y.w;}
int find(int x)
{
if(x==fa[x])return x;
return fa[x]=find(fa[x]);
}
void kruskal()
{
sort(edge+,edge+ct+,cmp);
for(int i=;i<=n;i++)fa[i]=i;
for(int i=;i<=ct;i+=)
{
int u=edge[i].to;
int v=edge[i^].to;
if(find(u)!=find(v))
{
cost+=edge[i].w;
fa[find(u)]=find(v);
use[i]=;
use[i^]=;
}
}
}
void dfs(int x)
{
vis[x]=;
for(int i=head[x];i;i=edge[i].next)
{
int u=edge[i].to;
if(!use[i]||vis[u])continue;
// printf("u=%d\n",u);
// printf("x=%d——u=%d\n",x,u);
if(dp[x].v>edge[i].w)
{
dp[u].v=dp[x].v;
dp[u].bh=dp[x].bh;
}
else
{
// printf("u=%d x=%d\n",u,x);
dp[u].v=edge[i].w;
// printf("dp[%d].v=%d\n",u,dp[u].v);
dp[u].bh=i;
}
dfs(u);
}
}
void add(int x,int y,int z)
{
ct++;
edge[ct].to=y;
edge[ct].next=head[x];
edge[ct].w=z;
head[x]=ct;
}
int main()
{
scanf("%d",&n);
mp["Park"]=++cnt;
for(int i=;i<=n;i++)
{
int x;
scanf("%s %s",&s1,&s2);
scanf("%d",&x);
if(!mp[s1])mp[s1]=++cnt;
if(!mp[s2])mp[s2]=++cnt;
if(mp[s1]==)
{
e[++ed].to=mp[s2];
e[ed].w=x;
continue;
}
if(mp[s2]==)
{
e[++ed].to=mp[s1];
e[ed].w=x;
continue;
}
// edge[++ct]=(mp[s2],head[mp[s1]],x);head[mp[s1]]=ct;
// edge[++ct]=(mp[s1],head[mp[s2]],x);head[mp[s2]]=ct;
add(mp[s2],mp[s1],x);
add(mp[s1],mp[s2],x);
}
// for(int i=2;i<=ct;i++)
// printf("w=%d to=%d\n",edge[i].w,edge[i].to);
scanf("%d",&m);
kruskal();
sort(e+,e+ed+,cmp);
for(int i=;i<=ed;i++)
{
int u=e[i].to;
if(!lk[find(u)])
{
cost+=e[i].w;
lk[find(u)]=;
use2[i]=;
reg++;
}
}
vis[]=;
for(int i=;i<=ed;i++)
{
if(!use2[i])continue;
dp[e[i].to].v=-;
dfs(e[i].to);
}
// for(int i=1;i<=n;i++)
// printf("i=%d v=%d bh=%d\n",i,dp[i].v,dp[i].bh);
// for(int i=1;i<=n;i++)
// printf("dp[%d]=%d\n",i,dp[i].v);
while(reg<m)
{
int mx=-;
int d,k;
for(int i=;i<=ed&&reg<m;i++)
{
if(use2[i])continue;
int u=e[i].to;
if(dp[u].v-e[i].w>mx)
{
mx=dp[u].v-e[i].w;
// cout<<dp[u].v<<" "<<e[i].w<<endl;
d=u;k=i;
}
}
// printf("mx=%d d=%d k=%d\n",mx,d,k);
if(mx<=)break;
cost-=mx;
use[dp[d].bh]=;
use2[k]=;
reg++;
dp[d].v=-;
memset(vis,,sizeof vis);
vis[d]=;
dfs(d);
}
printf("Total miles driven: %d\n",cost);
return ;
}

失败版

代码如下:

#include<iostream>
#include<cstdio>
#include<map>
#include<cstring>
#include<algorithm>
#include<string>
using namespace std;
int n,m,ct,cnt,fa[],cost,reg,key[],mne[],inf=0x3f3f3f3f;
string s1,s2;
map<string, int>mp;
struct N{
int hd,to,w;
}edge[];
struct NN{
int w,u,v;
}dp[];
bool in[][];
int sid[][];
bool cmp(N x,N y){return x.w<y.w;}
int find(int x)
{
if(x==fa[x])return x;
return fa[x]=find(fa[x]);
}
void kruskal()
{
sort(edge+,edge+ct+,cmp);
// for(int i=1;i<=ct;i++)
// printf("w=%d u=%d v=%d\n",edge[i].w,edge[i].hd,edge[i].to);
for(int i=;i<=cnt;i++)fa[i]=i;//
for(int i=;i<=ct;i++)
{
int u=edge[i].hd;
int v=edge[i].to;
if(u==||v==)continue;
if(find(u)!=find(v))
{
cost+=edge[i].w;
fa[find(u)]=find(v);
in[u][v]=in[v][u]=;
}
}
}
void dfs(int x,int f)
{
for(int u=;u<=cnt;u++)
{
if(!in[x][u]||u==f)continue;
if(dp[u].w==-)
{
if(dp[x].w>sid[x][u])
dp[u]=dp[x];
else
{
dp[u].w=sid[x][u];
dp[u].u=x;dp[u].v=u;
}
}
dfs(u,x);
}
}
int main()
{
scanf("%d",&n);
mp["Park"]=++cnt;
memset(sid,0x3f,sizeof sid);
for(int i=;i<=n;i++)
{
int x;
cin>>s1>>s2>>x;
if(!mp[s1])mp[s1]=++cnt;
if(!mp[s2])mp[s2]=++cnt;
int m1=mp[s1],m2=mp[s2];//!
sid[m1][m2]=sid[m2][m1]=min(sid[m1][m2],x);
edge[++ct].w=x;
edge[ct].hd=m1;edge[ct].to=m2;
}
scanf("%d",&m);
kruskal();
// for(int i=1;i<=cnt;i++)
// for(int j=1;j<=cnt;j++)
// if(in[i][j])printf("in[%d][%d]=%d\n",i,j,in[i][j]);
// cout<<cost<<endl;
memset(mne,0x3f,sizeof mne);
for(int i=;i<=cnt;i++)
{
if(sid[i][]==inf)continue;
int cr=find(i);
if(mne[cr]>sid[i][])
{
mne[cr]=sid[i][];
key[cr]=i;
}
}
for(int i=;i<=cnt;i++)//
{
if(mne[i]==inf)continue;
// cost+=mne[i];
cost+=sid[][key[i]];//
in[][key[i]]=in[key[i]][]=;
reg++;
}
for(int j=reg+;j<=m;j++)
{
memset(dp,-,sizeof dp);
dp[].w=-inf;
for(int i=;i<=cnt;i++)
{
if(in[i][])dp[i].w=-inf;
// else dp[i].w=-1;
}
dfs(,-);
int mn=inf;
int d;
for(int i=;i<=cnt;i++)
{
// if(sid[i][1]==inf)continue;
if(sid[i][]-dp[i].w<mn)
{
mn=sid[i][]-dp[i].w;
d=i;
}
}
if(mn>=)break;
cost+=mn;
in[dp[d].u][dp[d].v]=in[dp[d].v][dp[d].u]=;
in[][d]=in[d][]=;
}
printf("Total miles driven: %d\n",cost);
return ;
}

poj1639顶点度限制生成树的更多相关文章

  1. POJ1639顶点度限制最小生成树

    题目:http://poj.org/problem?id=1639 见汪汀的<最小生成树问题的拓展>. 大体是先忽略与根节点相连的边,做一遍kruscal,得到几个连通块和一个根节点: 然 ...

  2. poj1639 Picnic Planning,K度限制生成树

    题意: 矮人虽小却喜欢乘坐巨大的轿车,车大到能够装下不管多少矮人.某天,N(N≤20)个矮人打算到野外聚餐.为了集中到聚餐地点,矮人A 要么开车到矮人B 家中,留下自己的轿车在矮人B 家,然后乘坐B ...

  3. 【POJ 1639】 Picnic Planning (最小k度限制生成树)

    [题意] 有n个巨人要去Park聚会.巨人A和先到巨人B那里去,然后和巨人B一起去Park.B君是个土豪,他家的停车场很大,可以停很多车,但是Park的停车场是比较小.只能停k辆车.现在问你在这个限制 ...

  4. poj 1639 最小k度限制生成树

    题目链接:https://vjudge.net/problem 题意: 给各位看一下题意,算法详解看下面大佬博客吧,写的很好. 参考博客:最小k度限制生成树 - chty - 博客园  https:/ ...

  5. 最小k度限制生成树

    [题目描述] 给你一个图,n个点,m条边,求一颗生成树满足如下条件: (1)结点1的度不超过k. (2)在(1)条件下所求生成树最小. [算法引入] 最小k度限制生成树,就是指有特殊的某一点的度不能超 ...

  6. lesson2-完全图、补图和顶点度

    (一).完全图.偶图与补图 1.每两个不同的顶点之间都有一条边相连的简单图称为完全图 (complete graph).在同构意义下,n个顶点的完全图只有一个,记为 2.所谓具有二分类(X, Y)的偶 ...

  7. Picnic Planning POJ - 1639(度限制生成树)

    解题报告   题意理解 给定一张N个点,M个边的无向图,求出无向图的一颗最小生成树,但是我们要求一号节点的入度不可以超过给定的整数S 也就是一个最小生成树,要求它的一号节点,最多只能和S个节点相连. ...

  8. poj1639,uva1537,uvalive2099,scu1622,fzu1761 Picnic Planning (最小限制生成树)

    Picnic Planning Time Limit: 5000MS   Memory Limit: 10000K Total Submissions: 10742   Accepted: 3885 ...

  9. 图的生成树(森林)(克鲁斯卡尔Kruskal算法和普里姆Prim算法)、以及并查集的使用

    图的连通性问题:无向图的连通分量和生成树,所有顶点均由边连接在一起,但不存在回路的图. 设图 G=(V, E) 是个连通图,当从图任一顶点出发遍历图G 时,将边集 E(G) 分成两个集合 T(G) 和 ...

随机推荐

  1. svn hooks 实现自动更新

    搞来搞去,原来是hooks 下面的脚本名称必须是post-commit才可以, 写成fly-commit一直不行.晕死~~~ https://serverfault.com/questions/144 ...

  2. Android二维码工具zxing使用

    二维码在我们生活中随处可见.在我眼里简直能够用"泛滥"来形容啦.那怎样在我们Android项目中扫描识别二维码或生成二维码图片呢? 我们通常使用的开源框架是zxing.在githu ...

  3. electron 缓存目录 禁用缓存

    C:\Users\Administrator\AppData\Roaming\linksame // 禁用缓存 app.commandLine.appendSwitch("--disable ...

  4. vue2.0 自定义 折叠列表(Accordion)组件

    1.自定义  折叠列表 Accordion.vue (1)sass  版本 <!-- 折叠列表 组件 --> <template> <nav :class="$ ...

  5. CSDN - 进程结束后new出的内存会回收吗?

    http://blog.csdn.net/stanjiang2010/article/details/5386647     关键词:内存回收  

  6. ffmpeg 错误 real-time buffer [USB2.0 Camera] [video input] too full or near too full (101% of size: 30412)

    利用ffmpeg 获取USB 或者本地摄像机视频,并将视频编码后保存本地文件或者发送到远端流媒体服务经常会出现 类似real-time buffer [USB2.0 Camera] [video in ...

  7. idea刷新项目、清除项目缓存

    点击File -> Invalidate caches ,点击之后在弹出框中点击确认,之后软件就自动重启了

  8. 为基于 x86 的 Android* 游戏选择合适的引擎

    摘要 游戏开发者知道 Android 中蕴藏着巨大的机遇. 在 Google Play 商店的前 100 款应用中,约一半是游戏应用(在利润最高的前 100 款应用中.它们所占的比例超过 90%). ...

  9. php跳转

    header("Location: http://bbs. lampbrother.net"); header("refresh:0;url=./login.php&qu ...

  10. mysql中索引的使用

    索引是加速查询的主要手段,特别对于涉及多个表的查询更是如此.本节中,将介绍索引的作用.特点,以及创建和删除索引的语法. 使用索引优化查询 索引是快速定位数据的技术,首先通过一个示例来了解其含义及作用. ...