文章标题 UVALive 6062:Reduce the Maintenance Cost(双联通分量缩点)
来源:互联网 发布:2017淘宝注册用户数量 编辑:程序博客网 时间:2024/06/11 23:07
Reduce the Maintenance Cost
题意:在有n(n <= 10000)个点的无向图上,定义有m条边,每条边有自己的长度L,还有一个维护值val=N*L,其中N的定义是
N=破坏掉这条边时有多少点对不连通。
每条边的val值需要连接这条边两个点中的一个点来承担,现在每个点有一个初始值,问怎样分配使得所有点中最大的值最小。
分析:可以知道的是,只有桥才有val值,其他不是桥的边的val值都是0,因为没有点对会由于这条边被删除而不连通,所以我们可以通过tarjan缩点然后重新建树(森林),这样新建的树(森林)中的边就是桥的,而桥可以通过树形DP来求出每个子树的节点数。
代码:
#include <iostream>#include <cstdio>#include <cstring>#include <string>#include <queue>#include <set>#include <map>#include <algorithm>#include <math.h>#include <vector>using namespace std;typedef long long ll;const int mod=1e9+7;const int maxn=1e5+10;ll a[maxn];int n,m;ll mid;struct Edge{ int from,to,nex; ll w; bool cnt;//是否为桥 }edge[maxn];int head[maxn],tot;int Low[maxn],dfn[maxn],st[maxn],belong[maxn];int idx,top;int block; //联通块的数目 bool Instack[maxn];int bridge;//桥的数目 int num[maxn];void init(){ tot=0;memset (head,-1,sizeof (head)); memset (dfn,0,sizeof (dfn)); memset (Instack,false,sizeof (Instack)); memset (num,0,sizeof (num)); idx=top=block=bridge=0;}void addedge(int u,int v,int w){ edge[tot]=Edge{u,v,head[u],w,0}; head[u]=tot++;}void Tarjan(int u,int pre){ Low[u]=dfn[u]=++idx; st[top++]=u; Instack[u]=true; for (int i=head[u];i!=-1;i=edge[i].nex){ int v=edge[i].to; if (v==pre)continue; if (!dfn[v]){ Tarjan(v,u); if (Low[u]>Low[v])Low[u]=Low[v]; if (Low[v]>dfn[u]){ bridge++;edge[i].cnt=true;edge[i^1].cnt=true; } }else if (Instack[v]&&Low[u]>dfn[v]){ Low[u]=dfn[v]; } } if (Low[u]==dfn[u]){ block++; int v; do{ v=st[--top]; Instack[v]=false; belong[v]=block; num[block]++; }while (v!=u); }}struct node {//重新建图用的节点 int u,v,from,to,nex;//from表示的是这条边在原来的图上连接的两个节点,下面用来+val值用的 ll d;}e[maxn];int first[maxn];void add(int u,int v,int from,int to,ll d){ e[tot]=node{u,v,from,to,first[u],d}; first[u]=tot++; }int sz[maxn],fa_id[maxn];//fa_id[u]用来标记第几条边 void dfs(int u,int fa){//计算每个节点的孩子数 sz[u]=num[u];fa_id[u]=-1; for (int i=first[u];i!=-1;i=e[i].nex){ int v=e[i].v; if (v==fa){ fa_id[u]=i; continue; } dfs(v,u); sz[u]+=sz[v]; }} //计算每条边的权值int vis[maxn]; void dfs2(int u,int fa,int treenode){//treenode树的节点数 vis[u]=1; for (int i=first[u];i!=-1;i=e[i].nex){ int v=e[i].v; if (v==fa){ e[i].d*=(ll)sz[u]*(ll)(treenode-sz[u]); e[i^1].d=e[i].d; continue; } dfs2(v,u,treenode); }}void work(){//计算每个节点的孩子数目,和每条桥的价值 memset (sz,0,sizeof (sz)); for (int i=1;i<=block;i++){ if (sz[i]==0)dfs(i,-1); } memset (vis,0,sizeof (vis)); for (int i=1;i<=block;i++){ if (vis[i]==0)dfs2(i,-1,sz[i]); } }ll dp[maxn];bool DFS(int u,int fa){ vis[u]=1; for (int i=first[u];i!=-1;i=e[i].nex){ int v=e[i].v; if (v==fa)continue; if (!DFS(v,u))return false; } if (fa_id[u]!=-1){ int oldfrom=e[fa_id[u]].from,oldto=e[fa_id[u]].to; ll val=e[fa_id[u]].d; if (dp[oldfrom]+val<=mid)dp[oldfrom]+=val;//尽可能加在叶子节点 else if (dp[oldto]+val<=mid)dp[oldto]+=val; else return false; } return dp[u]<=mid;}bool ok(){ for (int i=1;i<=n;i++)dp[i]=a[i]; memset (vis,0,sizeof (vis)); for (int i=1;i<=block;i++){ if (vis[i]==0){ if (!DFS(i,-1))return false; } } return true;}int main(){ int T; scanf ("%d",&T); int cas=1; while (T--){ init(); scanf ("%d%d",&n,&m); ll hi=(ll)1e18; ll lo=0; for (int i=1;i<=n;i++){ scanf ("%lld",&a[i]); lo=max((ll)a[i],lo); } int u,v,w; for (int i=0;i<m;i++){ scanf ("%d%d%d",&u,&v,&w); addedge(u,v,w);addedge(v,u,w); } for (int i=1;i<=n;i++)if (!dfn[i])Tarjan(i,-1); int tot2=tot; memset (first,-1,sizeof (first));tot=0; for (int i=0;i<tot2;i+=2){ int u=edge[i].from,v=edge[i].to,w=edge[i].w; if (belong[u]==belong[v])continue; add(belong[u],belong[v],u,v,w);//重新建图 add(belong[v],belong[u],v,u,w); } work();//计算每个节点的孩子数目,和每条桥的价值 ll ans=hi+1; while (lo<=hi){ mid=(lo+hi)/2; if (ok()){ hi=mid-1; ans=min(ans,mid); }else lo=mid+1; } printf ("Case %d: %lld\n",cas++,ans); } return 0;}/*32 1 5 10 1 2 106 6 10 20 30 40 50 60 1 2 1 2 3 1 1 3 1 1 4 6 1 5 6 4 6 23 1 10 20 30 2 3 10*/
阅读全文
0 0
- 文章标题 UVALive 6062:Reduce the Maintenance Cost(双联通分量缩点)
- uvalive 6206 Reduce the Maintenance Cost
- UVa 12587 Reduce the Maintenance Cost(Tarjan + 二分 + DFS)
- 文章标题 POJ 1236 : Network of Schools (强联通分量+缩点)
- UVA 12587 Reduce the Maintenance Cost
- UVA 12587 Reduce the Maintenance Cost 解题报告
- 点双联通分量
- 双联通分量缩点模板
- hdu 5739(点双联通分量 )
- The Perfect Stall+spoj+强联通分量+缩点
- uva1364 - Knights of the Round Table 点-双联通分量
- 强联通分量+缩点
- 点双联通分量模板
- (点双联通分量模板)POJ 2942 Knights of the Round Table 圆桌骑士
- Uva 12587 Reduce the Maintenance Cost 边双连通+树形dp+贪心
- 割点,割边,强联通分量,点双联通分量,边双联通分量
- UVALive5796点双联通分量or边双联通分量
- 点双联通分量和边双联通分量小结
- HDU-6184-Counting Stars(广西邀请赛C题)(数据结构优化)
- Linux权限与命令的关系
- 使用 Sublime Text + Markdown 写博客
- Hdu 3622 Bomb Game 2-SAT+二分
- Java中的常量和变量
- 文章标题 UVALive 6062:Reduce the Maintenance Cost(双联通分量缩点)
- Ubuntu 安装Clion
- TCP连接和关闭的过程
- 理解Batch Normalization
- 挑选出只依赖表的视图, 并得到相应的创建脚本
- OpenJudge百炼-2967-特殊日历计算-C语言-日期处理
- IOS QLPreviewController的简单使用及如何隐藏toolbar上的Action按钮
- java语言基础(89)——多线程(线程控制)
- android.hardware.camera2详解(实时更新,未完待续...)