最小树形图/朱刘算法……表示稍微记录一下

来源:互联网 发布:淘宝网店加盟电话 编辑:程序博客网 时间:2024/05/17 02:56

大概就是那么几步……呃…

1) 每个点找到权值最小的入边,记录为In[i];

2) 【假装是一只定根的图】判有无除了根节点之外的独立节点,如果有的话那这个图必然不连通 于是直接return -1

3) 然后开始找环,至于在这种有n条边的图上找环的事,参考noip2015提高组D1T2

4) 找环的时候顺手把环缩了(标记一下,创建新的节点)

5) 然后更新 新图 的每个节点之间的距离,于是就会出现下面这种鬼畜的东西↓↓↓


说明一下为什么出边的权不变,入边的权要减去in [u]。对于新图中的最小树形图T,设指向人工节点的边为e。将人工节点展开以后,e指向了一个环。假设原先e是指向u的,这个时候我们将环上指向u的边 in[u]删除,这样就得到了原图中的一个树形图。我们会发现,如果新图中e的权w'(e)是原图中e的权w(e)减去in[u]权的话,那么在我们删除掉in[u],并且将e恢复为原图状态的时候,这个树形图的权仍然是新图树形图的权加环的权,而这个权值正是最小树形图的权值。所以在展开节点之后,我们得到的仍然是最小树形图。逐步展开所有的人工节点,就会得到初始图的最小树形图了。                           ——摘自百度百科 最小树形图(看代码看不懂的那一段


关于为什么 在给点重新编号的时候,计算每个新的点之间的距离 是这样奇怪的公式

假设是点i到点集vj(也就是新点vj)的距离,vj由n个点组成(vj1,vj2,vj3.....vjn)

dis[i][vj]=min{dis[i][vjk]-in[vik]}(1<=k<=n)

但是点集vj到点i的距离却是

dis[vj][i]=min{dis[vjk][i]}(1<=k<=n)

相当于是每条边都减去它指向的那个点的最小入边长度(如果这条边两边的点不在同一个集合中的话)


6) 最后,默默表示,细节什么的,真的,很重要 orzorzorz,用左闭右开区间,【左闭右闭WA到半夜一点的某表示……对自己的信仰产生了怀疑


最后附上呆马,虽然丑哭了,也许还会又WA又T又RE

题目在……呃……这里的learn那道题

#include<cstdio>#include<algorithm>#include<cstring>using namespace std;int n,m;int S=0;const int INF=0x3f3f3f3f;int aim[55];int num[55],cnt_node=1;struct t1{int frm,to,nxt,lth;}edge[10057];int cnt_edge=0;int fst[557];void addedge(int x,int y,int z){edge[++cnt_edge].to=y;edge[cnt_edge].frm=x;edge[cnt_edge].nxt=fst[x];edge[cnt_edge].lth=z;fst[x]=cnt_edge;}void init(){for(int i=1;i<=n;++i){for(int j=num[i]+1;j<num[i+1];++j)addedge(j,j-1,0);addedge(num[n+1],num[i],0);}while(m--){int a,b,c,d,e;scanf("%d%d%d%d%d",&a,&b,&c,&d,&e);addedge(num[a]+b,num[c]+d,e);}}//========================================================================int ans=0;int col[557];int cnt_col;int pre[557];int In[557];int vis[557];int zhuliu(int root,int NE,int NV){for(;;){memset(In,INF,sizeof(In));memset(pre,-1,sizeof(pre));//初始化每个点的Infor(int i=1;i<=NE;++i)if(edge[i].lth<In[edge[i].to]&&edge[i].to!=edge[i].frm)In[edge[i].to]=edge[i].lth,pre[edge[i].to]=edge[i].frm;//判有没有独立节点for(int i=0;i<NV;++i){if(i==root)continue;if(In[i]==INF)return -1;}//判环,缩环 cnt_col=0;memset(vis,-1,sizeof(vis));memset(col,-1,sizeof(col));In[root]=0;for(int i=0;i<NV;++i){ans+=In[i];int now=i;while(vis[now]!=i&&col[now]==-1&&now!=root){vis[now]=i;now=pre[now];}if(now!=root&&!(~col[now])){for(int tmp=pre[now];tmp!=now;tmp=pre[tmp])col[tmp]=cnt_col;col[now]=cnt_col++;}}//如果没有环就表示,树建好啦 if(!cnt_col)return ans;//给节点标新序号        for(int i=0;i<NV;i++)            if(!(~col[i]))col[i]=cnt_col++;//按照 入边长度-=In[i] 的规则更新每个新节点之间的距离for(int i=1;i<=NE;++i){int tt=edge[i].to;edge[i].frm=col[edge[i].frm];edge[i].to=col[edge[i].to];if(edge[i].frm!=edge[i].to)edge[i].lth-=In[tt];}NV=cnt_col;root=col[root];}}int main(){memset(fst,0,sizeof(fst));memset(edge,0,sizeof(edge));num[0]=0;while(scanf("%d%d",&n,&m)!=EOF&&(n||m)){for(int i=1;i<=n;++i)scanf("%d",&aim[i]),++aim[i],num[i+1]=num[i]+aim[i];init();printf("%d\n",zhuliu(num[n+1],cnt_edge,num[n+1]+1));}return 0;} 




0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 在学校校服丢了怎么办 高中没进重点班怎么办 孩子不懂学不想学怎么办 孩子小学数学学不懂怎么办 入学籍系统提交了没分班怎么办 被监考老师抓了作弊怎么办 作弊被老师抓到了怎么办? 中考作弊给抓到怎么办 考试作弊证据没得监控怎么办 考试作弊被领导发现了怎么办 黄冈讲课视频看不了怎么办 高中学校不给转学籍怎么办 兴山香溪大酒店欠钱不还怎么办 黑坑青鱼滑口怎么办 不交物业费物业怎么办 车牌刮了一点漆怎么办 电脑光驱线坏了怎么办 做系统不读光驱怎么办 光盘放进电脑没反应怎么办 不服省高院裁定维持原判怎么办 咖啡和酒一起喝怎么办 跟法官联系不上怎么办 四维没有预约到怎么办 钥匙锁在车里怎么办 如果孩子很叛逆骂人打人怎么办 错过了今年规培怎么办 枣木怎么办才能搞直了 高中生和家里闹意见离家出走怎么办 校长信箱实名举报了怎么办 枣子吃多了胀气怎么办 红枣吃多了会怎么办 宁波南苑e家会员卡怎么办 宁波社保卡丢了怎么办 奶茶汉堡店经营不好改怎么办 军人保障卡丢了怎么办 军人保障卡丢失了怎么办 军人保障卡掉了怎么办 椎基底动脉供血不足怎么办 颈椎压迫神经脑供血不足怎么办 脑部基底动脉轻度狭窄怎么办 胸壁疼痛我该怎么办