文章目录

  • 差分约束
    • 题目-区间选点II
    • 输入输出
    • 解题
    • 代码
  • 拓扑序列-kahn
    • 题目-猫猫向前冲
    • 输入输出
    • 解题
    • 代码
  • 强连通图SCC-kosaraju
    • 题目-班长竞选
    • 输入输出
    • 解题
    • 代码

差分约束

题目-区间选点II

给定一个数轴上的 n 个区间,要求在数轴上选取最少的点使得第 i 个区间 [ai, bi] 里至少有 ci 个点

输入输出

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

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

输出样例

6

解题

  • 不等式组
    求x3 - x0的最大值。

    观察x3 - x0的性质,我们如果可以通过不等式的两两加和得到c个形如 x3 - x0 <= Ti 的不等式,那么 min{ Ti | 0 <= i < c } 就是我们要求的x3 - x0的最大值。于是整理出以下三个不等式:

    1.  (3)                       x3 - x0 <= 8
      
    2.  (2) + (5)                 x3 - x0 <= 9
      
    3.  (1) + (4) + (5)           x3 - x0 <= 7
      

    这里的T等于{8, 9, 7},所以min{ T } = 7,答案就是7。

  • 最短路
    以dijkstra为例。

    由于这个图比较简单,我们可以枚举所有的路线,发现总共三条路线,如下:

    1.   0 -> 3                       长度为8
      
    2.   0 -> 2 -> 3                  长度为7+2 = 9
      
    3.   0 -> 1 -> 2 -> 3             长度为2 + 3 + 2 = 7
      

    没错与不等式最大值求解相似。

  • 差分约束
    如若一个系统由n个变量和m个不等式组成,并且这m个不等式对应的系数矩阵中每一行有且仅有一个1和-1,其它的都为0,这样的系统称为差分约束( difference constraints )系统。引例中的不等式组可以表示成如图三-1-1的系数矩阵。

    则原先的不等式可以变成了以下形式:d[u] + w(u, v) >= d[v]
     if(d[u] + w(u, v) < d[v]) {d[v] = d[u] + w(u, v);}
  • 最大值和最小值
    上面说的是求最大值时,转化为<=的差分约束系统,求最短路径。
    如果是最小值可以用>=的差分约束,这道题找最少选点,使用>=差分约束。
    另外,>=<之间可以转换,比如:a=b可以转化为a<=b或者a>=b,a<=b转化为-a>=-b。

  • 设计
    本题中,用sum数组表示到达i点一共选了sum个点。对于输入的ai,bi,ci可以构成差分约束,而且sum[ i ]要满足0<=sum[ i ] - sum[ i-1 ]<=1。

代码

#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>using namespace std;const int N=50005;
int head[N],ep=0,sum[N],n;
bool vis[N];
struct edge{int to,w,next;
}e[N*3]; void add_(int u,int v,int w){e[++ep].next=head[u];e[ep].w=w;e[ep].to=v;head[u]=ep;
}void SPFA(int s){memset(vis,0,sizeof(vis));int u,v,w;queue<int> q;q.push(s);vis[s]=1;while(!q.empty()){u=q.front();q.pop();vis[u]=0;for(int i=head[u];i;i=e[i].next){v=e[i].to;w=e[i].w;if(sum[v]<sum[u]+w){sum[v]=sum[u]+w;if(!vis[v]){q.push(v);vis[v]=1;}}}}
}int main(){int a,b,w,x=0;int minx=1e9,maxx=-1e9;cin>>n;memset(head,0,sizeof(head));for(int i=0;i<n;i++){cin>>a>>b>>w;a+=2;b+=2;minx=min(minx,a-1);maxx=max(maxx,b);add_(a-1,b,w);}for(int i=minx;i<=maxx;i++){add_(i,i-1,-1);add_(i-1,i,0);}for(int i=0;i<=maxx;i++){sum[i]=-1e9;}sum[minx]=0;SPFA(minx);cout<<sum[maxx]<<endl;
}

拓扑序列-kahn

题目-猫猫向前冲

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

输入输出

输入有若干组,每组中的第一行为二个数N(1<=N<=500),M;其中N表示猫猫的个数,M表示接着有M行的输入数据。接下来的M行数据中,每行也有两个整数P1,P2表示即编号为 P1 的猫猫赢了编号为 P2 的猫猫。
给出一个符合要求的排名。输出时猫猫的编号之间有空格,最后一名后面没有空格!
其他说明:符合条件的排名可能不是唯一的,此时要求输出时编号小的队伍在前;输入数据保证是正确的,即输入数据确保一定能有一个符合要求的排名。
输入样例

4 3
1 2
2 3
4 3
1
2
3

输出样例

1 2 4 3

解题

  • 拓扑排序
    在一个图中,如果有一条边从a指向b,那么我们称a在b前面,或在到达a之前不可能到达b,这类似我们选课时候的先行课程和课程之间的关系。
    下面一个例子就能说明拓扑排序。
  • kahn
    kahn算法正是找出拓扑排序的算法。
    首先把图中入度为0(即没有先行节点)的节点放入队列,从队列中的点开始找出它下一个能到的节点并放入队列(如果之间没有放入过的话)。
  • 设计
    本题中,每个比赛结果如:a胜b,都可以表示为边。
    最小字典输出,可以吧kahn中的队列换成优先队列。

代码

#include<iostream>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
/***G++能过,C++没过*/
const int N=505;
int inDeg[N], head[N],n;struct edge {int to,nxt;edge(int a,int b) {to=a;nxt=b;}
};
vector<edge> eg;
vector<int> vec;
void addEdge(int u,int v) {edge e(v,head[u]);eg.push_back(e);head[u]=eg.size()-1;inDeg[v]++;
}void kahn() {int u,v;priority_queue< int,vector<int>,greater<int> > q;for(int i=1; i<=n; i++) {if(!inDeg[i]) {q.push(i);}}while(!q.empty()) {u=q.top();q.pop();vec.push_back(u);for(int i=head[u]; i; i=eg[i].nxt) {v=eg[i].to;if(--inDeg[v]==0) {q.push(v);}}}for(int i=0; i<vec.size()-1; i++) {cout<<vec[i]<<" ";}cout<<vec[vec.size()-1];
}
int main() {int m,a,b;while(cin>>n) {cin>>m;memset(inDeg,0,sizeof(inDeg));memset(head,0,sizeof(head));eg.clear();vec.clear();eg.push_back(edge(0,0));for(int i=0; i<m; i++) {cin>>a>>b;addEdge(a,b);}kahn();cout<<endl;}
}

强连通图SCC-kosaraju

题目-班长竞选

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

输入输出

本题有多组数据。第一行 T 表示数据组数。每组数据开始有两个整数 N 和 M (2 <= n <= 5000, 0 <m <= 30000),接下来有 M 行包含两个整数 A 和 B(A != B) 表示 A 认为 B 合适。
对于每组数据,第一行输出 “Case x: ”,x 表示数据的编号,从1开始,紧跟着是最高的票数。 接下来一行输出得票最多的同学的编号,用空格隔开,不忽略行末空格!
样例输入

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

样例输出

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

解题

  • 强连通图
    有向图G中,每个点都能相互到达成为强连通分量。
    强连通分量SCC:强连通子图。
    例子说明。

  • DFS序列
    在dfs中有前序序列,后序序列等等。
    现在我们要说逆后序序列,即颠倒后序序列就是逆后序序列。其它不再多说
  • kosaraju
    kosaraju算法能找出SCC,且能为缩点做准备
    先贴一张图

    图中a是原图,b是反图即所有方向颠倒
    首先在原图dfs1找出逆后序序列。
    在逆后序序列中,最后一个一定是其他点能到达的,而第一个点一定能达到其它点。
    在a图中,无论是从abeSCC开始还是cdSCC开始,最后结束的一定是abeSCC中的点,因为abeSCC可以到其他点,其他点不能到abeSCC的点。
    找到逆后序序列后,按照序列dfs2,这次用反图b
    可以看到,abeSCC在序列最前面,而在反图中它是唯一一个不会达到其它点的SCC。
    那么用dfs2能到达的点都是abeSCC的成员,找到之后,排除abeSCC后,下一个不会到其它点的是cdSCC,依次找出所有SCC。
  • 缩点
    图c就是缩点之后的图,SCC中的点作为一个点,构成新的图。
    缩点过程可以在dfs2中完成,找到的所有点都归为一个SCC点,并且给一个不重复的编号。
    如果dfs2中知道了已经做过SCC标记的点比如dcSCC找到了abeSCC(abeSCC在dcSCC标记前一定标记过,刚刚说了标记过就抛弃所以dcSCC不会把abeSCC的点加入到自己队伍里),找就表示连个SCC之间有单向一条路径,加入到新构建的SCC图中。
  • 设计
    本题中,每个投票都有传递性。
    在SCC中所有点都支持其它任何一个点(不支持自己),那么每个点的支持数都是SCC成员数-1。
    而在缩点后的SCC图c图中,如果一个SCC(如abe)能到达另一个SCC(如dc),说明前者支持后者。这时候就用到了dfs3。
    支持数最高的一定在出度为零的SCC中。
    缩点图也可以根据反图构造。

代码

#include<iostream>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;const int N = 5005;
vector<int> G[N], RG[N], SG[N], S, GG[N];
int ps[N], pscnt, k, n, scc[N], outDeg[N], maxs, sum;
bool vis[N];void addEdge(int a, int b) {G[a].push_back(b);RG[b].push_back(a);
}
void dfs1(int s) {vis[s] = 1;for (unsigned int i = 0; i < G[s].size(); i++) {int x = G[s][i];if (!vis[x]) {dfs1(x);}}ps[pscnt++] = s;
}
void dfs2(int s) {vis[s] = 1;scc[s] = k;GG[k].push_back(s);if (SG[k].empty()) {SG[k].push_back(1);}else {SG[k][0]++;}for (unsigned int i = 0; i < RG[s].size(); i++) {int x = RG[s][i];if (!vis[x]) {dfs2(x);}else {if (scc[x] != k) {SG[k].push_back(scc[x]);outDeg[scc[x]]++;}}}
}
void Kosaraju() {memset(vis, 0, sizeof(vis));memset(outDeg, 0, sizeof(outDeg));k = -1, pscnt = 0;for (int i = 0; i < n; i++) {if (!vis[i]) {dfs1(i);}}memset(vis, 0, sizeof(vis));for (int i = n - 1; i >= 0; i--) {if (!vis[ps[i]]) {k++;dfs2(ps[i]);}}
}
void dfs3(int s) {vis[s] = 1;sum += SG[s][0];for (unsigned int i = 1; i < SG[s].size(); i++) {if (!vis[SG[s][i]]) {dfs3(SG[s][i]);}}
}
void fun(int tt) {maxs = 0;for (int i = 0; i <= k; i++) {if (outDeg[i] == 0) {memset(vis, 0, sizeof(vis));sum = -1;dfs3(i);if (sum > maxs) {maxs = sum;S.clear();S.push_back(i);}elseif (sum == maxs) {S.push_back(i);}}}int p = 0;for (unsigned int i = 0; i < S.size(); i++) {for (unsigned int j = 0; j < GG[S[i]].size(); j++) {ps[p++] = GG[S[i]][j];}}sort(ps, ps + p);cout << "Case " << tt << ": " << maxs << endl;for (int i = 0; i < p - 1; i++) {cout << ps[i] << " ";}if(p>0)cout << ps[p - 1] << endl;
}
int main() {int t, m, a, b, tt = 1;cin >> t;while (tt <= t) {cin >> n >> m;for (int i = 0; i < n; i++) {G[i].clear(), RG[i].clear(), SG[i].clear();GG[i].clear();}S.clear();for (int i = 0; i < m; i++) {cin >> a >> b;addEdge(a, b);}Kosaraju();fun(tt);tt++;}
}

Week8 :差分约束,拓扑排序和kahn,强连通图和kosaraju相关推荐

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

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

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

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

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

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

  4. 拓扑排序(kahn算法和dfs算法)

    拓扑排序 1定义 2两种拓扑排序算法 2.1kahn算法 2.1dfs算法(染色) 1定义 拓扑排序(Topological Sorting) 给定一张 有向无环图 ,排出所有顶点的一个序列A,满足: ...

  5. 拓扑排序总结(Kahn算法)

    随便记录点东西 在拓扑排序中,排序结果唯一当且仅当所有顶点间具有全序关系. 快速排序不是稳定的(偏序关系),因为相同元素之间的关系无法确定. 插入排序是稳定的(全序关系),因为相同元素可以通过位置的先 ...

  6. 拓扑排序【Kahn算法(bfs)和dfs求拓扑序列及判环】

    拓扑排序 对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,该排序满足这样的条件--对于图中的任意两个结点u和v,若存在一条有 ...

  7. 程序设计思维 B - 猫猫向前冲(拓扑排序、Kahn算法)

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

  8. 拓扑排序:Kahn算法

    问题概述:有n个比赛队,编号为从1到n,比赛结束后,裁判委员会要将所有参赛队伍从前往后依次排名,但现在 裁判委员会不能直接获得每个队的比赛成绩,只知道每场比赛的结果,即P1赢P2(用P1 P2表示)这 ...

  9. 基于入度的拓扑排序(Kahn's Algorithm)

    本文中的图用邻接链表来表示 拓扑排序只针对于有向无环图(DAG)才能完成,所以可以利用拓扑排序来判断一个有向图是否有环. 某一点的入度:图中指向该顶点的边的个数 图1 :DAG 以上图简单说明,点0的 ...

最新文章

  1. uniapp背景图片android不显示,uni-app网络图片在app不显示,小程序显示
  2. 定义命令别名(alias)
  3. C#编程之委托与事件(一)
  4. FDDB--无约束人脸检测数据集
  5. Windows10 开机跳过密码验证
  6. 弘辽科技:淘宝店铺评分太低是降权了吗?
  7. 流行音乐混音风格 流行音乐混音的压缩技巧
  8. hpe 服务器 稳定性6,将NAA ID与运行ESXi 6.7的HPE服务器上的物理驱动器托架位置相关联...
  9. 测试手机单核性能软件,跑分软件Geekbench公布“作弊”名单:华为6款手机上榜...
  10. 中信期货财务因题专题报告:财务因子之单因子测试
  11. 真约数求法 c语言,数学:求一个数的真约数(因数)的个数及所有约数之和
  12. 基于TSMaster的UDS刷写教程
  13. SNAT、DNAT、NPT
  14. Linux安装配置Git
  15. 26.CF1000F One Occurrence
  16. C#源代码—姓名 请输入老师的编号、姓名、职称和部门
  17. android 沙盒存储,Android Q存储机制-沙盒机制
  18. CLion:The C compiler identification is unknown, CMake Error;Cygwin的安装配置方法
  19. 什么是social media?
  20. linux apt install rpm,使用apt-rpm 简化你的redhat,fedora rpm包管理

热门文章

  1. 51nod-1299 监狱逃离(贪心)
  2. 微信与支付宝钱包的竞争分析
  3. win8计算机不显示视频图标,如何解决Win8.1桌面图标显示不正常的问题?
  4. Mac Terminal 美化
  5. 凶残的挖矿脚本,奴役我数千机器!
  6. return false和return true
  7. 02-SA8155P ADB数据传输
  8. Vue ElementUI el-button 修改样式
  9. 工作日志3——模型代码
  10. python预测股票价格_使用机器学习预测股票价格的愚蠢简便方法