Let's define a forest as a non-directed acyclic graph (also without loops and parallel edges). One day Misha played with the forest consisting of n vertices. For each vertex v from 0 to n - 1 he wrote down two integers, degreev and sv, were the first integer is the number of vertices adjacent to vertex v, and the second integer is the XOR sum of the numbers of vertices adjacent to v (if there were no adjacent vertices, he wrote down 0).
Next day Misha couldn't remember what graph he initially had. Misha has values degreev and sv left, though. Help him find the number of edges and the edges of the initial graph. It is guaranteed that there exists a forest that corresponds to the numbers written by Misha.
The first line contains integer n (1 ≤ n ≤ 216), the number of vertices in the graph.
The i-th of the next lines contains numbers degreei and si (0 ≤ degreei ≤ n - 1, 0 ≤ si < 216), separated by a space.
In the first line print number m, the number of edges of the graph.
Next print m lines, each containing two distinct numbers, a and b (0 ≤ a ≤ n - 1, 0 ≤ b ≤ n - 1), corresponding to edge (a, b).
Edges can be printed in any order; vertices of the edge can also be printed in any order.
3 2 3 1 0 1 0
2 1 0 2 0
2 1 1 1 0
1 0 1
The XOR sum of numbers is the result of bitwise adding numbers modulo 2. This operation exists in many modern programming languages. For example, in languages C++, Java and Python it is represented as "^", and in Pascal — as "xor".
题目大意:给你一个数字n,代表n个节点,编号为0~n-1,接下来n行,分别对应每个节点的信息,每行两个数字,第一个数字是与该点连接的点的个数,第二个数字是与该点连接的所有点的异或结果,让你求出该图的边的条数和每条边的两端编号。(注:题中说明该图是无向无环图,就是一棵树)
解题思路:
这是一个无向无环图,也就是一棵树,那么它就肯定有叶子结点,叶子节点的度数为1,此时它相邻点的异或结果实际上就是所求点的编号了。然后把跟叶子节点相邻的点的度数减去1,代表把叶子节点去除,此时异或结果是有变的。需要用本来的异或结果跟该叶子节点再异或一次,就得出除了这个叶子节点外其他点的异或值了,即a^b^c^a=b^c。
代码如下:
#include <cstdio>
#include <queue>
using namespace std;
int in[70000];//存每个点连接的点的个数
int orsum[70000];//存每个点的异或结果
int main()
{
int n;
scanf("%d",&n);
queue<int>que;
pair<int,int>bian[70000];//申请一个存边的数组
for(int i=0;i<n;i++)
{
scanf("%d%d",&in[i],&orsum[i]);
if(in[i]==1)//如果某个点连接的点的个数是1,那么说明它是最下面一层的点,把该点放到队列里面
{
que.push(i);
}
}
int cnt=0;//统计边的个数
while(!que.empty())
{
int from=que.front();
que.pop();
if(in[from]==1)//这个判断,不能少,因为 第一个例子中0的度数在该过程中会变成0
{
int to=orsum[from];
bian[cnt].first=from;
bian[cnt].second=to;
cnt++;
in[from]--;
in[to]--;
orsum[to]=orsum[to]^from;//更新异或结果
if(in[to]==1)
{
que.push(to);
}
}
}
printf("%d\n",cnt);
for(int i=0;i<cnt;i++)
{
printf("%d %d\n",bian[i].first,bian[i].second);
}
return 0;
}