D. Lazy Student
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output
Student Vladislav came to his programming exam completely unprepared as usual. He got a question about some strange algorithm on a graph — something that will definitely never be useful in real life. He asked a girl sitting next to him to lend him some cheat papers for this questions and found there the following definition:
The minimum spanning tree T of graph G is such a tree that it contains all the vertices of the original graph G, and the sum of the weights of its edges is the minimum possible among all such trees.
Vladislav drew a graph with n vertices and m edges containing no loops and multiple edges. He found one of its minimum spanning trees and then wrote for each edge its weight and whether it is included in the found tree or not. Unfortunately, the piece of paper where the graph was painted is gone and the teacher is getting very angry and demands to see the original graph. Help Vladislav come up with a graph so that the information about the minimum spanning tree remains correct.
Input
The first line of the input contains two integers n and m () — the number of vertices and the number of edges in the graph.
Each of the next m lines describes an edge of the graph and consists of two integers aj and bj (1 ≤ aj ≤ 109, bj = {0, 1}). The first of these numbers is the weight of the edge and the second number is equal to 1 if this edge was included in the minimum spanning tree found by Vladislav, or 0 if it was not.
It is guaranteed that exactly n - 1 number {bj} are equal to one and exactly m - n + 1 of them are equal to zero.
Output
If Vladislav has made a mistake and such graph doesn't exist, print - 1.
Otherwise print m lines. On the j-th line print a pair of vertices (uj, vj) (1 ≤ uj, vj ≤ n, uj ≠ vj), that should be connected by the j-th edge. The edges are numbered in the same order as in the input. The graph, determined by these edges, must be connected, contain no loops or multiple edges and its edges with bj = 1 must define the minimum spanning tree. In case there are multiple possible solutions, print any of them.
Examples
Input
4 5
2 1
3 1
4 0
1 1
5 0
Output
2 4
1 4
3 4
3 1
3 2
Input
3 3
1 0
2 1
3 1
Output
-1
题目大意:
给你n个点,m条无向边,接下来m行,每行表示当前边的信息:边的权值,边是否属于最小生成树(1表示属于0表示不属于)。
问你能否对应每条边构建出来两个顶点,使得最终构成的图满足给出的条件。
思路:
1、首先根据最小生成树的贪心策略可知(克鲁斯卡尔算法),我们先对所有给出的边进行排序。
2、根据克鲁斯卡尔算法过程可知,按照从小到大排序之后的边如果属于最小生成树,其当前边的作用一定是使得两个点连通(而且加上这条边之前这两个点没有连通)。如果不属于最小生成树,其当前边的两个点一定在之前就已经连通了。那么根据这个特性,而且这个题是要输出任意解,那么我们初始化答案变量:ans1=1,ans2=2;如果当前边属于了最小生成树,对应这条边就设定为(1,2),然后ans1++,ans2++,再遇到吓一条属于最小生成树的边之后,这条边就设定为(2,3),然后ans1++,ans2++,依次类推。
3、以上,我们就解决了如果当前边属于最小生成树边的情况的解。那么如果当前遇到的边不属于最小生成树的边我们要如何处理呢?
上边已经说过了,如果按照了从小到大边权值排序之后的这条边如果不属于最小生成树,那么这条边的两个顶点一定是已经连通了的,那么需要设定的边其实也不难想到:
①设定queue【10000】;queue【i】=v,初始化v=i+2。
②那么考虑这样一个情况:
1 1
2 1
3 1
4 0
那么在遇到4 0之前,我们已经在图中加入了三条边:(1,2)(2,3)(3,4),那么这个时候遇到了4 0,这条边不属于最小生成树的边,这个时候我们枚举一层for,从点1开始,一直枚举到ans1-1为止,如果queue【i】<ans2,那么就可以加入图中:(i,queue【i】)这条边。显然,其这条边的两点,一定在之前就已经连通了,加入的这条边,也已经保证了的确不属于最小生成树的边。
如果没有枚举到可行边,那么很可惜,这个时候要输出-1了。
4、思路建立完毕,剩下的内容就是实现代码了。
Ac代码:
#include<stdio.h>
#include<string.h>
#include<queue>
#include<algorithm>
using namespace std;
struct node
{
int w,op,pos;
}a[120000];
int cmp(node a,node b)
{
if(a.w==b.w)return a.op>b.op;
else return a.w<b.w;
}
queue<int >s[100005];
int output[120000][2];
int n,m;
void init()
{
for(int i=1;i<=100005;i++)
{
s[i].push(i+2);
}
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
init();
memset(output,0,sizeof(output));
for(int i=0;i<m;i++)
{
scanf("%d%d",&a[i].w,&a[i].op);
a[i].pos=i;
}
sort(a,a+m,cmp);
int ans1=1;
int ans2=2;
int x=1,y=3;
int flag=0;
/*
printf("---------------\n");
for(int i=0;i<m;i++)
{
printf("%d %d\n",a[i].w,a[i].op);
}
printf("----------------\n");
*/
for(int i=0;i<m;i++)
{
if(a[i].op==1)
{
output[a[i].pos][0]=ans1;
output[a[i].pos][1]=ans2;
ans1++;
ans2++;
}
else
{
int tmp=0;
for(int j=0;j<ans1;j++)
{
int u=s[j].front();
if(u<=ans2-1)
{
s[j].pop();
tmp=1;
output[a[i].pos][0]=j;
output[a[i].pos][1]=u;
u++;
s[j].push(u);
break;
}
}
if(tmp==0)
{
flag=1;
break;
}
}
}
if(flag==1)
{
printf("-1\n");
}
else
{
for(int i=0;i<m;i++)
{
printf("%d %d\n",output[i][0],output[i][1]);
}
}
}
}