Codeforces 605B 构造
2015-12-11 00:04
375 查看
Codeforces 605B
题目链接:
http://codeforces.com/problemset/problem/605/B
题意:
给一个图n个点(<=1e5)和m条边(<=1e5),其中有一些边是这个图最小生成树的边。
问此图是否合法。不合法输出-1(包括最小生成树不满足),合法输出一种给每条边分配结点的方案。
思路:
构造题。主要流程是先按照原图生成一个最小生成树然后往树上加边。
试过一种构造 1 - 2 - 3 - 4 - … - n的方法形成最小生成树,但是每次新边应该加在那个地方不好讨论。
然后构造了这样一颗最小生成树:1-2,1-3,….,1-n。然后每次新加边的时候,假设选的是u和v,那么只要满足ValOfNow < max(ValOf(1-u), ValOf(1-v))即可。可分最小生成树边和非最小生成树边进行排序,每次非最小生成树边匹配掉最小的一条树边即可。
那么问题就变成了如何去枚举两条树边。
树边A从小到大枚举,树边B也从小到大枚举并且小于树边A。这样这组组合中有效参与运算的树边是树边A的值Valof(A).因为A是从小到大枚举的,而非树边也是从小到大枚举,所以非树边每次都匹配掉当前A最小且B最小的那个组合即可。
源码:
题目链接:
http://codeforces.com/problemset/problem/605/B
题意:
给一个图n个点(<=1e5)和m条边(<=1e5),其中有一些边是这个图最小生成树的边。
问此图是否合法。不合法输出-1(包括最小生成树不满足),合法输出一种给每条边分配结点的方案。
思路:
构造题。主要流程是先按照原图生成一个最小生成树然后往树上加边。
试过一种构造 1 - 2 - 3 - 4 - … - n的方法形成最小生成树,但是每次新边应该加在那个地方不好讨论。
然后构造了这样一颗最小生成树:1-2,1-3,….,1-n。然后每次新加边的时候,假设选的是u和v,那么只要满足ValOfNow < max(ValOf(1-u), ValOf(1-v))即可。可分最小生成树边和非最小生成树边进行排序,每次非最小生成树边匹配掉最小的一条树边即可。
那么问题就变成了如何去枚举两条树边。
树边A从小到大枚举,树边B也从小到大枚举并且小于树边A。这样这组组合中有效参与运算的树边是树边A的值Valof(A).因为A是从小到大枚举的,而非树边也是从小到大枚举,所以非树边每次都匹配掉当前A最小且B最小的那个组合即可。
源码:
#include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <algorithm> #include <iostream> #include <string> #include <queue> #include <map> #include <set> using namespace std; const int MAXN = 100000 + 5; int n, m; struct D { int u, v; int mark; int x, y; }d[MAXN]; bool cmp(D a, D b) { if(a.v == b.v) return a.u < b.u; return a.v > b.v; } bool cmp2(D a, D b){return a.mark < b.mark;} int num[MAXN]; long long sum[MAXN]; int cnt[MAXN]; set<int>s; int main() { while(scanf("%d%d", &n, &m) != EOF){ for(int i = 0 ; i < m ; i++) scanf("%d%d", &d[i].u, &d[i].v), d[i].mark = i; sort(d, d + m, cmp); int ok = 1; for(int i = 0 ; i < n - 1 ; i++) d[i].x = 1, d[i].y = i + 2; for(int i = 1 ; i <= n ; i++) cnt[i] = i + 1; memset(num, 0, sizeof(num)); for(int i = 1 ; i <= n ; i++) num[i] = i - 1; int now = 0; long long tot = 0; int u = 3, v = 2; for(int i = n - 1; i < m ; i++){ while(now < n - 1 && d[i].u >= d[now].u) tot += num[++now]; // printf("i = %d, now = %d\n", i, now); if(tot <= 0){ ok = 0; break; } tot--; d[i].x = u, d[i].y = v; v++; if(v >= u){u++, v = 2;} } if(ok == 0) printf("-1\n"); else{ sort(d, d + m, cmp2); for(int i = 0 ; i < m ; i++) printf("%d %d\n", d[i].x, d[i].y); } } return 0; }
相关文章推荐
- 我要开始学习计算机的基础知识
- SQLServer内置函数
- PDF文档压缩
- BZOJ1503 [NOI2004]郁闷的出纳员
- HDU 1133 Buy the Ticket 卡特兰数 JAVA
- java学习——函数
- 每天一点进步:Spark RDD三大特性
- Servlet网上售票问题引发线程安全问题的思考
- Java Servlet生成JSON格式数据并用jQuery显示的方法
- JSP使用Servlet过滤器进行身份验证的方法
- Python操作MySQL数据库9个实用实例
- Python实现各种排序算法的代码示例总结
- 深入源码解析Python中的对象与类型
- 一篇文章入门Python生态系统(Python新手入门指导)
- PHP异常处理Exception类
- 基于PHP如何把汉字转化为拼音
- PHP开发中AJAX技术的简单应用
- 搭建Vim为自定义的PHP开发工具的一些技巧
- 使用PHP+AJAX让WordPress动态加载文章的教程
- linux ps命令技巧