CF 335 div.1-B/div.2-D/605 B Lazy Student

来源:互联网 发布:天刀成女脸型数据 编辑:程序博客网 时间:2024/04/30 07:39

题目链接:http://codeforces.com/problemset/problem/605/B

题目大意:有一个网(加权图),无向,无环,给出你他的顶点个数n(2<=n<=100000)和边的个数m( 1<=m<=100000且n-1<=m<=n*(n-1)/2 ),然后有m行,每行是一个整数和一个bool变量,第一个数表示这个边的权值,第二个数,1表示这条边在这个图的最小生成树(MST)里,0表示不在MST里。求满足条件的每个边连接的两个顶点序号,有多种情况,给出其中一种即可,如果不存在输出-1,存在就输出m行,每行两个数表示这条边所连接的两个顶点(输出顺序要与输入顺序对应)。

解:都有点不太想写,这套题都是构造题0.0,没有完全的构造出来,最后还是看的题解。

假设有两个顶点集U和V,初始时,U中只有1号顶点,V中有其他的顶点。

先将所有的边按升序排序,权值一样的话将属于MST的排到前面,然后从小到大处理每条边。

遇到一个新的属于MST的边就把这条边连接一个V中的顶点,并把这个顶点从V中移除,加到U中,如果是不属于MST的,就让这个边连接U中任意两个未连接的顶点。不合法的情况就是在连接U中任意两个未连接的顶点时没有点可连。

两种构造方法。一,对于MST的里的边就是1-2,1-3,,,1-n,

对于不是MST里的边,假设当前U里有x个顶点,设l和r是连接这条边连接的两个点,那么每次,如果l<r,就作连接,然后l++,否则就是l==r,那就让r++,l=2。非法情况就是r++时,如果r>x,就是非法,输出-1.

二,对于MST里的边就是1-2,2-3,,,(n-1)-n。

对于不是MST里的边,假设当前U里有x个顶点,设l和r是连接这条边连接的两个点,那么每次,如果l < r-1,就作连接,然后l++,否则就是l==r-1,那就让r++,l=1。非法情况就是r++时,如果r>x,就是非法,输出-1.

其实就是构造,反正构造出一种合理的方法就好。


代码:

#include <iostream>#include <cstdio>#include <cstdlib>#include <cstring>#include <algorithm>using namespace std;int n, m;//bool U[100005], V[100005];int connect[100005][2];struct edge_unit{int k, i, f;bool operator <(edge_unit a){if (this->k < a.k)return true;else if (this->k == a.k)return this->f>a.f;elsereturn false;}}edge[100005];bool work(){int l = 2, r = 2, p = 1;for (int i = 0; i < m; ++i){if (edge[i].f){connect[edge[i].i][0] = 1;connect[edge[i].i][1] = ++p;}else{if (l == r){++r; l = 2;if (r > p)return 0;}connect[edge[i].i][0] = l++;connect[edge[i].i][1] = r;}}return 1;}int main(){//freopen("input.txt", "r", stdin);scanf("%d%d", &n, &m);int x, flag;for (int i = 0; i < m; ++i){scanf("%d%d", &x, &flag);edge[i].k = x;edge[i].f = flag;edge[i].i = i;}sort(edge, edge + m);if (work())for (int i = 0; i < m; ++i)printf("%d %d\n", connect[i][0], connect[i][1]);elseprintf("-1\n");//system("pause");//while (1);return 0;}

0 0