博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
BZOJ2521:[SHOI2010]最小生成树(最小割)
阅读量:7103 次
发布时间:2019-06-28

本文共 2818 字,大约阅读时间需要 9 分钟。

Description

Secsa最近对最小生成树问题特别感兴趣。他已经知道如果要去求出一个n个点、m条边的无向图的最小生成树有一个Krustal算法和另一个Prim的算法。另外,他还知道,某一个图可能有多种不同的最小生成树。例如,下面图 3中所示的都是图 2中的无向图的最小生成树:

 

当然啦,这些都不是今天需要你解决的问题。Secsa想知道对于某一条无向图中的边AB,至少需要多少代价可以保证AB边在这个无向图的最小生成树中。为了使得AB边一定在最小生成树中,你可以对这个无向图进行操作,一次单独的操作是指:先选择一条图中的边 P1P2,再把图中除了这条边以外的边,每一条的权值都减少1。如图 4所示就是一次这样的操作:

Input

输入文件的第一行有3个正整数n、m、Lab分别表示无向图中的点数、边数、必须要在最小生成树中出现的AB边的标号。
接下来m行依次描述标号为1,2,3…m的无向边,每行描述一条边。每个描述包含3个整数x、y、d,表示这条边连接着标号为x、y的点,且这条边的权值为d。
输入文件保证1<=x,y<=N,x不等于y,且输入数据保证这个无向图一定是一个连通图。

Output

输出文件只有一行,这行只有一个整数,即,使得标号为Lab边一定出现最小生成树中的最少操作次数。

Sample Input

4 6 1
1 2 2
1 3 2
1 4 3
2 3 2
2 4 4
3 4 5

Sample Output

1

HINT

1个样例就是问题描述中的例子。

1<=n<=500,1<=M<=800,1<=D<10^6

Solution

首先题目的操作其实可以看成给一条边权值加一……

首先对于权值比$lab$大的边,我们肯定是不需要管的,因为按照$kruskal$的过程,他们一定在$lab$的后面考虑。

而对于权值比$lab$小的,我们可以通过给他们不停加一使得权值超过$lab$从而靠后考虑。

可以发现,当$(u[lab],v[lab])$这条边会被算到最小生成树里面,只有在权值小于等于它的边加完后,$u[lab]$和$v[lab]$不在一个连通块内。我们把权值小于等于$l[lab]$的图建出来,现在问题变成,你可以用$l[lab]-l[i]+1$的代价砍掉一些边使得$u[lab]$和$v[lab]$不连通,最小割就好了。

Code

1 #include
2 #include
3 #include
4 #include
5 #include
6 #define N (1009) 7 #define INF (0x7f7f7f7f) 8 using namespace std; 9 10 struct Edge{
int to,next,flow;}edge[N<<1];11 int n,m,lab,u[N],v[N],l[N],Depth[N];12 int head[N],num_edge;13 queue
q;14 15 inline int read()16 {17 int x=0,w=1; char c=getchar();18 while (c<'0' || c>'9') { if (c=='-') w=-1; c=getchar();}19 while (c>='0' && c<='9') x=x*10+c-'0', c=getchar();20 return x*w;21 }22 23 void add(int u,int v,int l)24 {25 edge[++num_edge].to=v;26 edge[num_edge].next=head[u];27 edge[num_edge].flow=l;28 head[u]=num_edge;29 }30 31 int DFS(int x,int low,int t)32 {33 if (x==t || !low) return low;34 int f=0;35 for (int i=head[x]; i; i=edge[i].next)36 if (Depth[edge[i].to]==Depth[x]+1)37 {38 int Min=DFS(edge[i].to,min(low,edge[i].flow),t);39 edge[i].flow-=Min;40 edge[((i-1)^1)+1].flow+=Min;41 f+=Min; low-=Min;42 if (!low) break;43 }44 if (!f) Depth[x]=-1;45 return f;46 }47 48 bool BFS(int s,int t)49 {50 memset(Depth,0,sizeof(Depth));51 Depth[s]=1;52 q.push(s);53 while (!q.empty())54 {55 int x=q.front(); q.pop();56 for (int i=head[x]; i; i=edge[i].next)57 if (!Depth[edge[i].to] && edge[i].flow)58 {59 Depth[edge[i].to]=Depth[x]+1;60 q.push(edge[i].to);61 }62 }63 return Depth[t];64 }65 66 int Dinic(int s,int t)67 {68 int ans=0;69 while (BFS(s,t)) ans+=DFS(s,INF,t);70 return ans;71 }72 73 int main()74 {75 n=read(); m=read(); lab=read();76 for (int i=1; i<=m; ++i) u[i]=read(),v[i]=read(),l[i]=read();77 for (int i=1; i<=m; ++i)78 if (i!=lab && l[i]<=l[lab])79 {80 add(u[i],v[i],l[lab]-l[i]+1);81 add(v[i],u[i],l[lab]-l[i]+1);82 }83 printf("%d\n",Dinic(u[lab],v[lab]));84 }

转载于:https://www.cnblogs.com/refun/p/10523201.html

你可能感兴趣的文章
C#中文转换成拼音
查看>>
C语言程序设计实验第四次作业
查看>>
【转】C#自定义异常类简介
查看>>
hadoop(5)---yarn配置 --常用配置
查看>>
提高博客浏览量的几个小技巧
查看>>
模板Template
查看>>
ios-网络request请求
查看>>
多线程 线程间通信 wait,notify
查看>>
Linux中断(interrupt)子系统之一:中断系统基本原理【转】
查看>>
selenium 页面元素的内置属性
查看>>
ubuntu16.04 离线安装nginx
查看>>
Block、委托、回调函数原理剖析(在Object C语境)——这样讲还不懂,根本不可能!...
查看>>
ubuntu/debian/linux彻底卸载mysql
查看>>
debian彻底清理MYSQL
查看>>
内核编译出错解决
查看>>
SOA会不会造成IT黑洞
查看>>
添加用户到LDAP服务器
查看>>
Application、Session和Cookie
查看>>
查询存储过程所需参数
查看>>
测试调用接口
查看>>