【强联通分量缩点】【最长路】【spfa】CH Round #59 - OrzCC杯NOIP模拟赛day1 队爷的讲学计划
10分算法:对于城市网络为一条单向链的数据,
20分算法:对于n<=20的数据,暴力搜出所有的可能路径。 结合以上可以得到30分。
60分算法:分析题意可得使者会带着去的城市也就是这个城市所在强联通分量的其他城市,这个过程的代价也就是这个强联通分量的城市数-1,且他可以选择任何一个其中的城市离开这个强联通分量。于是我们求出所有强联通分量,记录下每一个包含的城市数,然后缩点。接下来再用dfs,由于数据是构造的,只能得到60分。
100分算法:在缩点之后,这个图变成了一个有向无环图,我们将一条边连向的SCC包含的城市数看做边权(<--其实一条边的边权是一个pair,pair.first为其连向的SCC包含的城市数;pair.second为原本的边权+其连向的SCC包含的城市数-1),这样问题就转化为了求一个有向无环图上的最长路径,利用DP或者Spfa或者其他的方法求解即可,本题没有构造卡Spfa的数据。
比赛的时候写的缩点+暴搜,被卡成60分。
//下划线为官方题解。
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
#define M 500001
#define N 100001
struct Node
{
int v,w;
Node(const int &a,const int &b){v=a;w=b;}
Node(){}
};
struct Edge
{
int u,v,w;
Edge(const int &a,const int &b,const int &c){u=a;v=b;w=c;}
Edge(){}
}edges[M];
vector<Node>ljb[M];
vector<int>vs,G[M],rG[M];
typedef vector<int>::iterator ITER;
typedef vector<Node>::iterator Edge_ITER;
int sum,n,m,x,y,z,anscity,cnt[N],cmp[N],anscost=;
bool vis[N];
void dfs(int U)
{
vis[U]=;
for(ITER it=G[U].begin();it!=G[U].end();it++)
if(!vis[*it])
dfs(*it);
vs.push_back(U);
}
void rdfs(int U)
{
vis[U]=;
cmp[U]=sum;
cnt[sum]++;
for(ITER it=rG[U].begin();it!=rG[U].end();it++)
if(!vis[*it])
rdfs(*it);
}
void scc()
{
for(int i=;i<=n;i++) if(!vis[i]) dfs(i);
memset(vis,,sizeof(vis));
ITER it=vs.end(); it--;
for(;;it--)
{
if(!vis[*it])
{
sum++;
rdfs(*it);
}
if(it==vs.begin()) break;
}
}
void dfs3(int U,int city,int cost)
{
if(city>anscity)
{
anscity=city;
anscost=cost;
}
else if(city==anscity && cost<anscost)
anscost=cost;
for(Edge_ITER it=ljb[U].begin();it!=ljb[U].end();it++)
dfs3((*it).v,city+cnt[(*it).v],cost+(*it).w+cnt[(*it).v]-);
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=;i<=m;i++)
{
scanf("%d%d%d",&x,&y,&z);
G[x].push_back(y);
rG[y].push_back(x);
edges[i]=Edge(x,y,z);
}
scc();
for(int i=;i<=m;i++)
if(cmp[edges[i].u]!=cmp[edges[i].v])
ljb[cmp[edges[i].u]].push_back(Node(cmp[edges[i].v],edges[i].w));
dfs3(cmp[],cnt[cmp[]],cnt[cmp[]]-);
printf("%d %d\n",anscity,anscost);
return ;
}
后来写的缩点+spfa,要注意所谓的spfa最长路是双关键字比较的,优先让pair.first最大化,再让pair.second最小化,重载下运算符就可以了。
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
#include<queue>
using namespace std;
#define INF 2147483647
#define M 500001
#define N 100001
queue<int>q;
struct Node
{
int v,w;
Node(const int &a,const int &b){v=a;w=b;}
Node(){}
}dis[N];
bool operator < (const Node &a,const Node &b)
{return a.v!=b.v ? a.v<b.v : a.w>b.w;}
Node operator + (const Node &a,const Node &b)
{return Node(a.v+b.v,a.w+b.w);}
struct Edge
{
int u,v,w;
Edge(const int &a,const int &b,const int &c){u=a;v=b;w=c;}
Edge(){}
}edges[M];
vector<Edge>ljb[M];
vector<int>vs,G[M],rG[M];
typedef vector<int>::iterator ITER;
typedef vector<Edge>::iterator Edge_ITER;
int sum,n,m,x,y,z,anscity,cnt[N],cmp[N],anscost=;
Node ans;
bool vis[N],inq[N];
void dfs(int U)
{
vis[U]=;
for(ITER it=G[U].begin();it!=G[U].end();it++)
if(!vis[*it]) dfs(*it);
vs.push_back(U);
}
void rdfs(int U)
{
vis[U]=; cmp[U]=sum; cnt[sum]++;
for(ITER it=rG[U].begin();it!=rG[U].end();it++)
if(!vis[*it]) rdfs(*it);
}
void scc()
{
for(int i=;i<=n;i++) if(!vis[i]) dfs(i);
memset(vis,,sizeof(vis));
ITER it=vs.end(); it--;
for(;;it--)
{
if(!vis[*it])
{
sum++;
rdfs(*it);
}
if(it==vs.begin()) break;
}
}
void spfa(const int &s)//Node.v权最大化的城市数,Node.w权为最小化的cost
{
for(int i=;i<=sum;i++) dis[i]=Node(-INF,INF);
dis[]=Node(cnt[s],cnt[s]-);
inq[]=; ans=Node(-,);
q.push();
while(!q.empty())
{
int cur=q.front();
for(Edge_ITER it=ljb[cur].begin();it!=ljb[cur].end();it++)
if(dis[(*it).u]<dis[cur]+Node((*it).v,(*it).w))
{
dis[(*it).u]=dis[cur]+Node((*it).v,(*it).w);
if(!inq[(*it).u])
{
q.push((*it).u);
inq[(*it).u]=;
}
}
q.pop(); inq[cur]=;
}
for(int i=;i<=n;i++) ans=max(ans,dis[i]);
printf("%d %d\n",ans.v,ans.w);
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=;i<=m;i++)
{
scanf("%d%d%d",&x,&y,&z);
G[x].push_back(y);
rG[y].push_back(x);
edges[i]=Edge(x,y,z);
}
scc();
for(int i=;i<=m;i++)
if(cmp[edges[i].u]!=cmp[edges[i].v])
ljb[cmp[edges[i].u]].push_back(Edge(cmp[edges[i].v],cnt[cmp[edges[i].v]],edges[i].w+cnt[cmp[edges[i].v]]-));
spfa();
return ;
}
【强联通分量缩点】【最长路】【spfa】CH Round #59 - OrzCC杯NOIP模拟赛day1 队爷的讲学计划的更多相关文章
- 【强联通分量缩点】【Tarjan】bzoj1051 [HAOI2006]受欢迎的牛
就是看是否有一些点,从其他任何点出发都可到达 定理:有向无环图中唯一出度为0的点,一定可以由任何点出发均可达. 所以缩点,若出度为零的点(强联通分量)唯一,则答案为该强联通分量中点的度数. 若不唯一, ...
- Tarjan求强联通分量+缩点
提到Tarjan算法就不得不提一提Tarjan这位老人家 Robert Tarjan,计算机科学家,以LCA.强连通分量等算法闻名.他拥有丰富的商业工作经验,1985年开始任教于普林斯顿大学.Tarj ...
- 【最小割】【Dinic】【强联通分量缩点】bzoj1797 [Ahoi2009]Mincut 最小割
结论: 满足条件一:当一条边的起点和终点不在 残量网络的 一个强联通分量中.且满流. 满足条件二:当一条边的起点和终点分别在 S 和 T 的强联通分量中.且满流.. 网上题解很多的. #include ...
- 【强联通分量缩点】【最短路】【spfa】bzoj1179 [Apio2009]Atm
缩点后转化成 DAG图上的单源最长路问题.spfa/dp随便. #include<cstdio> #include<queue> #include<algorithm&g ...
- 【强联通分量缩点】【搜索】bzoj2208 [Jsoi2010]连通数
两次dfs缩点,然后n次dfs暴搜. #include<cstdio> #include<vector> #include<cstring> using names ...
- 【POJ 1236 Network of Schools】强联通分量问题 Tarjan算法,缩点
题目链接:http://poj.org/problem?id=1236 题意:给定一个表示n所学校网络连通关系的有向图.现要通过网络分发软件,规则是:若顶点u,v存在通路,发给u,则v可以通过网络从u ...
- [BZOJ1051] [HAOI2006] 受欢迎的牛 (强联通分量)
Description 每一头牛的愿望就是变成一头最受欢迎的牛.现在有N头牛,给你M对整数(A,B),表示牛A认为牛B受欢迎. 这 种关系是具有传递性的,如果A认为B受欢迎,B认为C受欢迎,那么牛A也 ...
- poj 1236 强联通分量
大致题意给你有一个点数为n<=100的有向图. 求解两个子任务: 1:最少给多少个点信息,这些点的信息可以顺着有向边传遍全图. 2:最少要加多少条边,使得整个图强联通. 求强联通分量再缩点后得到 ...
- POJ 2186 强联通分量
点击打开链接 题意:牛A喜欢牛B,若牛B喜欢牛C,则牛A喜欢牛C,问最后多少牛被其它全部牛喜欢 思路:用强联通分量进行缩点,最后形成的图是有向无环图DAG.而拓扑序的值为DAG的长度,则加一,可是最后 ...
随机推荐
- [NOI2003] 文本编辑器 (splay)
复制炸格式了,就不贴题面了 [NOI2003] 文本编辑器 Solution 对于光标的移动,我们只要记录一下现在在哪里就可以了 Insert操作:手动维护中序遍历结果,即每次取中点像线段树一样一样递 ...
- [uva 1350]数位dp+二分
题目链接:https://vjudge.net/problem/38405 #include<bits/stdc++.h> using namespace std; ][]; ]; lon ...
- POJ3169:Layout(差分约束)
Layout Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 15705 Accepted: 7551 题目链接:http ...
- linux 下查看网卡工作速率
[root@hadoop058 ~]# mii-tool eth0: negotiated 100baseTx-FD, link ok 100M linux 下查看网卡工作速率 Ethtool是用于查 ...
- kubernetes 参考资料
kubernetes 参考资料 非常建议先花20分钟,完成这个官方的交互式指南:https://kubernetes.io/docs/tutorials/kubernetes-basics/ 这个教程 ...
- TCP(一)
TCP的特点:三次握手.四次挥手.可靠连接.丢包重传.所有的关键词都围绕着可靠传输. 实现可靠传输的核心机制:seq+ack.通过ack判断是否有丢包,是否需要重传. 三次握手 1)初始状态:clie ...
- 【poj3415-长度不小于k的公共子串个数】后缀数组+单调栈
这题曾经用sam打过,现在学sa再来做一遍. 基本思路:计算A所有的后缀和B所有后缀之间的最长公共前缀. 分组之后,假设现在是做B的后缀.前面的串能和当前的B后缀产生的公共前缀必定是从前往后单调递增的 ...
- 51nod K 汽油补给 大根堆+小根堆....
题目传送门 用优先队列瞎搞... 想着在每个地方 先算上一个点到这一个点要花费多少钱 这个用小根堆算就好 然后在这个地方加油 把油钱比自己多的替代掉 这个用大根堆维护一下 然后两个堆之间信息要保持互通 ...
- [BZOJ1602&BZOJ1787&BZOJ2144]树上LCA的算法巩固练习
简述求LCA的倍增算法 对于树上的所有节点,我们可以很轻松地通过dfs求出其直接的父亲节点以及其深度 通过类似RMQ的原理我们可以处理出每个节点的第2^i个父亲 //这个过程既可以在dfs之后双重循环 ...
- CentOS erlang安装
1. http://www.erlang.org/下载erlang,解压缩,进入目录,检查环境 alex$ cd otp_src_18. alex$ ./configure ************* ...