A-区间选点Ⅱ

题目描述

给定一个数轴上的 n 个区间,要求在数轴上选取最少的点使得第 i 个区间 [ai, bi] 里至少有 ci 个点
使用差分约束系统的解法解决这道题

Input

输入第一行一个整数 n 表示区间的个数,接下来的 n 行,每一行两个用空格隔开的整数 a,b 表示区间的左右端点。1 <= n <= 50000, 0 <= ai <= bi <= 50000 并且 1 <= ci <= bi - ai+1。

Output

输出一个整数表示最少选取的点的个数

Sample Input

5
3 7 3
8 10 3
6 8 1
1 3 1
10 11 1

Sample Output

6

解题思路

这道题要求用差分约束系统写。
先构造不等式组

  • 记sum[i]表示数轴上[0,i]之间选点的个数
  • 对于第i个区间[ai,bi]需要满足sum[bi]-sum[ai-1]>=ci,即sum[bi]>=ci+sum[ai-1],ai-1指向bi的边权重为ci,每次存储边,同时更新右端点

同时还需要保证sum是有意义的

  • 0<=sum[i]-sum[i-1]<=1,i-1指向i的边权重为0,i指向i-1的边权重为-1,从0至右端点,对每个单位区间添加这两条边

求解该差分约束系统的最小解,转化为 >= 不等式组用spfa跑最长路,答案为sum[max{bi}],b_max为右端点。

注意

因为存在不等式0<=sum[0]-sum[-1]<=1,所以将区间整体右移一个单位.

代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>using namespace std;const int inf=1e8;
const int N=50110;
const int M=50010*4;
int n,dis[N],head[N],vis[N],tot,b_max=0;
queue<int> q;struct Edge {int to,nxt,w;
}e[M];void add(int x,int y,int w) {e[++tot].to=y;e[tot].nxt=head[x];e[tot].w=w;head[x]=tot;
}void init() {for(int i=0;i<=50010;++i) {dis[i]=-inf;vis[i]=0;}tot=0;
}void spfa(int s) {q.push(s);dis[s]=0;vis[s]=1;while(!q.empty()) {int u=q.front();q.pop();vis[u]=0;for(int i=head[u]; i; i=e[i].nxt) {int v=e[i].to;if(dis[v]<dis[u]+e[i].w) {dis[v]=dis[u]+e[i].w;if(!vis[v]) {q.push(v);vis[v]=1;}}}}
}int main() {scanf("%d",&n);int a=0,b=0,c=0;init();for(int i=1;i<=n;++i) {scanf("%d%d%d",&a,&b,&c);a += 1,b += 1;add(a-1,b,c);if(b_max<b) b_max=b;}for(int i=1;i<=b_max;++i) {add(i,i-1,-1);add(i-1,i,0);}spfa(0);printf("%d\n",dis[b_max]);return 0;
}

B-猫猫向前冲

题目描述

众所周知, TT 是一位重度爱猫人士,他有一只神奇的魔法猫。
有一天,TT 在 B 站上观看猫猫的比赛。一共有 N 只猫猫,编号依次为1,2,3,…,N进行比赛。比赛结束后,Up 主会为所有的猫猫从前到后依次排名并发放爱吃的小鱼干。不幸的是,此时 TT 的电子设备遭到了宇宙射线的降智打击,一下子都连不上网了,自然也看不到最后的颁奖典礼。
不幸中的万幸,TT 的魔法猫将每场比赛的结果都记录了下来,现在他想编程序确定字典序最小的名次序列,请你帮帮他。

Input

输入有若干组,每组中的第一行为二个数N(1<=N<=500),M;其中N表示猫猫的个数,M表示接着有M行的输入数据。接下来的M行数据中,每行也有两个整数P1,P2表示即编号为 P1 的猫猫赢了编号为 P2 的猫猫。

Output

给出一个符合要求的排名。输出时猫猫的编号之间有空格,最后一名后面没有空格!

其他说明:符合条件的排名可能不是唯一的,此时要求输出时编号小的队伍在前;输入数据保证是正确的,即输入数据确保一定能有一个符合要求的排名。

Sample Input

4 3
1 2
2 3
4 3

Sample Output

1 2 4 3

解题思路

拓扑排序,前向星存图,有向无权。
Kahn算法:
存图后,入度为0的点加入队列,由于编号小的先输出,使用优先队列,设置为小根堆。
每次从堆中取出一个顶点u,加入ans,然后遍历u的所有边(u,v),并删除(即v的in_deg–),如果移除后邻接点v入度为0,将v加入堆中,不断重复上述过程,直到所有点加入ans即可。

代码

#include<iostream>
#include<cstdio>
#include<queue>
#include<vector>using namespace std;int n,m,in_deg[510],head[510],tot;
vector<int> ans;
priority_queue<int,vector<int>,greater<int>> q;struct Edge{int to,nxt;
}e[50010];void add(int u,int v) {e[++tot].to=v;e[tot].nxt=head[u];head[u]=tot;
}
void init() {for(int i=0;i<=n;++i) {head[i]=-1;in_deg[i]=0;}while(!q.empty()) q.pop();ans.clear();tot=0;
}int main() {int x=0,y=0;while(scanf("%d%d",&n,&m)!=EOF) {init();while(m--) {scanf("%d%d",&x,&y);add(x,y);in_deg[y]++;}for(int i=1;i<=n;++i) if(in_deg[i]==0) q.push(i);while(!q.empty()) {int u=q.top();q.pop();ans.push_back(u);for(int i=head[u];i!=-1;i=e[i].nxt) {int v=e[i].to;in_deg[v]--;if(in_deg[v]==0) q.push(v);}}for(int i=0;i<ans.size()-1;++i) printf("%d ",ans[i]);printf("%d\n",ans[ans.size()-1]);}return 0;
}

C-班长竞选

题目描述

大学班级选班长,N 个同学均可以发表意见 若意见为 A B 则表示 A 认为 B 合适,意见具有传递性,即 A 认为 B 合适,B 认为 C 合适,则 A 也认为 C 合适 勤劳的 TT 收集了M条意见,想要知道最高票数,并给出一份候选人名单,即所有得票最多的同学,你能帮帮他吗?

Input

本题有多组数据。第一行 T 表示数据组数。每组数据开始有两个整数 N 和 M (2 <= n <= 5000, 0 <m <= 30000),接下来有 M 行包含两个整数 A 和 B(A != B) 表示 A 认为 B 合适。

Output

对于每组数据,第一行输出 “Case x: ”,x 表示数据的编号,从1开始,紧跟着是最高的票数。 接下来一行输出得票最多的同学的编号,用空格隔开,不忽略行末空格!

Sample Input

2
4 3
3 2
2 0
2 13 3
1 0
2 1
0 2

Sample Output

Case 1: 2
0 1
Case 2: 2
0 1 2

解题思路

有向图SCC并缩点,互相可达与单向可达分开考虑。
对于属于第i个SCC的点来说,答案分为两部分(SCC[i]为第i个SCC中点的个数)——

  1. 当前SCC中的点,ans+=SCC[i]-1(去除自己)
  2. 其他SCC中的点,sum(SCC[j]),j可到达i

这种思路下很容易想到,得票最多一定出现在出度为0的SCC中!
那么在反图中,对每个入度为0的点dfs,累加能达到点的SCC[i],即可得到答案。

具体做法:
用Kosaraju求SCC
① 第一遍dfs遍历原图,得到原图的后序序列dfn
② 对后序序列从n开始逆向对所有点第二遍dfs(相当于对逆后序序列从头开始),c[i]中存储原始点i所属的SCC编号,SCC[i]为编号为i的SCC中点的个数

缩点
将同一个SCC的点合并成一个点,遍历反图中的每个点的邻接边,如果边的两端点不属于同一SCC则在缩点图中加入该边,加入边时,计数每个SCC入度,最终形成新的缩点图。

计算每个SCC获得的票数存入ans[i]
由题可知:同一SCC中的点获得票数相同为SCC-1
遍历缩点后的图,对于入度为0的点(缩点后的图源于反图,所以在原图就是出度为0的点,所有可以到达它的点,都给它投票),进行第三遍dfs计算每个缩点总共获得的票数(去除自己)

计算最大得票数max_ans
遍历原图的所有点,如果某点在所在的SCC的ans==max_ans,则输出该点

注意

原题序号为0-N-1,图中为1-N,因此最后应输出i-1。

代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>using namespace std;int t,n,m,tot1,tot2,tot,dcnt,scnt,sum,max_ans;
int h_org[5010],h_inv[5010],h_ctr[5010],vis[5010];
int dfn[5010],c[5010],scc[5010],in_deg[5010],ans[5010],s_vis[5010];struct Edge {int to,nxt;
}e_org[30010],e_inv[30010],e_ctr[30010];void add1(int u,int v) {//原图 e_org[++tot1].to=v;e_org[tot1].nxt=h_org[u];h_org[u]=tot1;
}void add2(int u,int v) {//反图 e_inv[++tot2].to=v;e_inv[tot2].nxt=h_inv[u];h_inv[u]=tot2;
}void add(int u,int v) {//缩点图 e_ctr[++tot].to=v;e_ctr[tot].nxt=h_ctr[u];h_ctr[u]=tot;in_deg[v]++;
}void dfs1(int x) {vis[x]=1;for(int i=h_org[x];i;i=e_org[i].nxt) {int y=e_org[i].to;if(!vis[y]) dfs1(y);}//后序dfn[++dcnt]=x;
} void dfs2(int x) {c[x]=scnt;scc[scnt]++;for(int i=h_inv[x];i;i=e_inv[i].nxt) {int y=e_inv[i].to;if(!c[y]) dfs2(y);}
}void dfs(int x) {s_vis[x]=1;sum+=scc[x];for(int i=h_ctr[x];i;i=e_ctr[i].nxt) {int y=e_ctr[i].to;if(!s_vis[y]) dfs(y);}
}void kosaraju() {dcnt=0,scnt=0;memset(c,0,sizeof c);memset(vis,0,sizeof vis);//正向遍历 for(int i=1;i<=n;++i) if(!vis[i]) dfs1(i);//逆后序;for(int i=n;i>=1;--i) if(!c[dfn[i]]) ++scnt,dfs2(dfn[i]);
}void shrink() {//缩点for(int x=1;x<=n;++x) {for(int i=h_inv[x];i;i=e_inv[i].nxt) {int y=e_inv[i].to;if(c[x]==c[y]) continue;add(c[x],c[y]);}}
}void init() {for(int i=0;i<=5010;++i) {h_org[i]=0;h_inv[i]=0;h_ctr[i]=0;dfn[i]=0;in_deg[i]=0;scc[i]=0;ans[i]=0;}sum=0;max_ans=0;tot1=0;tot2=0;tot=0;
}
int main() {scanf("%d",&t);int a=0,b=0;for(int k=1;k<=t;++k) {scanf("%d%d",&n,&m);init();for(int i=1;i<=m;++i) {scanf("%d%d",&a,&b);add1(a+1,b+1);add2(b+1,a+1);}kosaraju();shrink();for(int i=1;i<=scnt;++i) {if(!in_deg[i]) {sum=0;//每个入度为0的连通分量都要dfs memset(s_vis,0,sizeof s_vis);dfs(i);ans[i]=sum-1;if(max_ans<ans[i]) max_ans=ans[i];}}printf("Case %d: %d\n",k,max_ans);int flag=0;for(int i=1;i<=n;++i) {if(ans[c[i]]==max_ans) {if(!flag) {printf("%d",i-1);flag++;}else printf(" %d",i-1);}}printf("\n");  } return 0;
}

WEEK(8)作业——差分约束、拓扑排序(Kahn算法)、SCC(强连通分量)、DFS序、Kosaraju算法相关推荐

  1. week8作业/差分约束/拓扑排序/强连通图

    文章目录 A,D-区间选点II 题目: Input: Output: Sample Input: Sample Output: 题目分析: 代码: B-猫猫向前冲 题目: Input: Output: ...

  2. Awcing1192. 奖金(差分约束/拓扑排序)

    题目 由于无敌的凡凡在2005年世界英俊帅气男总决选中胜出,Yali Company总经理Mr.Z心情好,决定给每位员工发奖金. 公司决定以每个人本年在公司的贡献为标准来计算他们得到奖金的多少. 于是 ...

  3. Poj 1094 拓扑排序Kahn

    Poj 1094 拓扑排序Kahn Sorting It All Out Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 4133 ...

  4. 拓扑排序----Kahn算法和字典序最小的拓扑排序

    一.拓扑排序定义: 二.卡恩算法(Kahn): 1.Kahn算法介绍: 有向无环图DAG至少具有一个度数为0的顶点和一个度数为0的顶点. 证明:上述事实有一个简单的证明,即DAG不包含循环,这意味着所 ...

  5. (数据结构)有向图的拓扑排序 Kahn算法

    拓扑排序是对有向无圈图的顶点的一种排序,使得如果存在一条从vi到vj的路径,那么在排序中,vi必须出现在vj的前面. 首先,我们需要准备一个vector<int> link[maxn],l ...

  6. 拓扑排序(Kahn算法和基于DFS求解法)

    拓扑排序是对有向无环图(DAG)进行排序,从而找到一个序列.该序列满足对于任意一对不同的顶点u,v∈V,若G中存在一条从u->v的边,则在此序列中u在v前面. 拓扑排序也可以用来判断一个有向图是 ...

  7. DAG拓扑排序-Kahn算法

    拓扑排序就是对一个有向无环图进行排序,使其变成一个线性关系,并且保证其前后的位置关系不改,简言之,就是把一个偏序变成一个全序(线性序). 拓扑排序有两种算法,一种是借助DFS排序,另一种是卡恩算法,这 ...

  8. 拓扑排序Kahn算法

    拓扑排序 介绍 思路 操作过程 完美图解 代码模板 介绍 拓扑排序,整体是给出n个事件先后关系,来确定n个事件最终的先后关系 思路 很好理解 操作过程 我们可以理解成一个有向图如果x事件在y事件的前面 ...

  9. 拓扑排序-Kahn算法

    题目描述 众所周知, TT 是一位重度爱猫人士,他有一只神奇的魔法猫. 有一天,TT 在 B 站上观看猫猫的比赛.一共有 N 只猫猫,编号依次为1,2,3,-,N进行比赛.比赛结束后,Up 主会为所有 ...

最新文章

  1. pytorch_导入d2l_pytorch包问题
  2. cms监控android,CMSV9道路监控终端
  3. js利用tab键切换当前页面_JS实现的tab切换并显示相应内容模块功能示例
  4. 【OS学习笔记】九 实模式:从汇编的角度理解栈结构
  5. python图灵测试_最前沿:基于GAN和RL的思想来训练对话生成,通过图灵测试可期!...
  6. 程序设计与算法----递归之爬楼梯问题
  7. 如何利用极致业务基础平台做一个通用企业ERP之十一销售出库单设计
  8. 《公共安全视频监控联网信息安全技术要求》(国标GB/35114-2017)
  9. linux桌面只运行浏览器,4个Linux桌面上的轻量级图像浏览器
  10. Android对现有的apk进行修改(汉化,修改QQ尾巴)
  11. android pos机对接微信刷脸支付时如何做到双屏异显-2020年10月9日
  12. 什么是SAP GUI的client
  13. 酷体网--可以顶(dig)的运动空间
  14. 产品定位--如何进行互联网产品定位/制定产品目标?
  15. 桥接路由器总是掉线_无线路由器桥接完整教程(不会断网)【图文详解】
  16. 偶然发现的一篇文章 激励自己吧。
  17. 记一次spark两个大表join数据倾斜调优
  18. 输入汉字自动转为拼音(jsp实现方式)
  19. 出租屋路由器DHCP模式连接经常断网处理
  20. PAT (Advanced Level) Practice 1165 Block Reversing

热门文章

  1. 测试人眼中的车联网(比亚迪云服务-3.2.1)——车辆定位、寻车
  2. 面试测试开发工程师:用例篇
  3. 加州大学计算机硕士录取率是多少,加州大学发布2021录取数据,录取率全面下降,UCLA要跌破10%了!...
  4. 洛谷P1209 [USACO1.3]修理牛棚 Barn Repair----解题报告
  5. 量化投资实战(二)之配对交易策略---最短距离法
  6. 1.2线性代数之行列式,余子式及代数余子式
  7. 腾讯云数据库 TDSQL-之初体验
  8. 小米手机保护套自动锁屏功能
  9. 多测师肖sir___app测试(新增001)
  10. 诡异的QT脱离主界面弹出之前删除的UI子部件问题