您的位置:首页 > 其它

CodeForces 605 B.Lazy Student(构造)

2017-04-20 10:59 351 查看
Description

给出一个n个点m条边的图的每条边的边权和该条边是否是这张图的最小生成树的树边,问满足这些条件的图是否存在,如果存在则输出这张图,否则输出-1

Input

第一行输入两个整数n和m表示点数和边数,之后m行每行两个整数ai和bi分别表示第i条边的边权和第i条边是否是最小生成树的树边(2<=n<=1e5,1<=m<=1e5,n-1<=m<=n*(n-1)/2,1<=ai<=1e9)

Output

如果存在满足条件的图则按输入的边权顺序输出对应的边,否则输出-1

Sample Input

4 5

2 1

3 1

4 0

1 1

5 0

Sample Output

2 4

1 4

3 4

3 1

3 2

Solution

构造题,考虑求MST的过程,一条边u->v被淘汰是因为已经找到的MST集合中u->v已经通过边权更小的边可达了,那么在此题的构造中,我们先用给出的n-1条树边构造出一棵MST,然后看剩下的m-n+1条边是否能够通过合理的放置让其在求MST的过程中被淘汰,为使得这n-1条树边起到充分的作用,我们构造一个星型树,即1点分别连向2,3,…,n点形成一棵树,且1-2,1-3,…,1-n的边权递增,对于非树边,我们降序排,贪心的处理边权较大的边,因为边权较大的边不先处理掉的话一些树边的作用可能会被一些边权小的非树边浪费,每次以pos点为终点,起点s从2开始,pos点需满足边1-pos的权不大于当前要插入的边的权w,这样以来把w作为边权赋给s-pos边在求MST时必然会被1-pos边淘汰,每次s=pos时就令pos=pos-1换个终点,然后起点接着从2开始,如果终点也是2了说明当前处理的非树边无法通过树边淘汰掉了,进而无解。

注意到给树边和非树边分别排好序的主要好处就是用游标法优化了每次找pos的过程,时间复杂度O(mlogm)

Code

#include<cstdio>
#include<algorithm>
using namespace std;
#define maxn 111111
int n,m;
struct node
{
int w,flag,id,u,v;
bool operator<(const node &b)const
{
if(flag!=b.flag)return flag>b.flag;
if(flag)return w<b.w;
return w>b.w;
}
}a[maxn];
bool cmp(node a,node b)
{
return a.id<b.id;
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
for(int i=1;i<=m;i++)
{
scanf("%d%d",&a[i].w,&a[i].flag);
a[i].id=i;
}
sort(a+1,a+m+1);
for(int i=1;i<n;i++)
a[i].u=1,a[i].v=i+1;
int gg=0;
int pos=n;
while(pos>=3&&a[pos-1].w>a
.w)pos--;
for(int i=n,j=pos,k=2;i<=m;i++)
{
if(j==2)
{
gg=1;
break;
}
while(a[i].w<a[j-1].w)
{
j--,k=2;
if(j==2)
{
gg=1;
break;
}
}
if(k==j)j--,k=2;
if(j==k)
{
gg=1;
break;
}
a[i].u=k++,a[i].v=j;
}
if(gg)printf("-1\n");
else
{
sort(a+1,a+m+1,cmp);
for(int i=1;i<=m;i++)printf("%d %d\n",a[i].u,a[i].v);
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: