codeforces 605 B. Lazy Student(最小生成树+构造)

题意
给出n个点,m条边,给出m条边的权值和是否被选定为最小生成树的边,0未选,1选定。问能否构建出这颗最小生成树,能的话输出边的连接

思路:
构造题目,考虑最简单的方法,先将边权从小到大排序,并且被选中的放在前面,以便后面操作。
选中的边:直接连在1上面
未选中的边:考虑最小生成树定义,假如我现在连在1上的点有x条,那么可以将未选中的边放在(2,3)(2,4)(3, 4)…直到(x-1,x) ,因为我们直接连在1上的是已选定的边,那么未选中的边就不能小于左右点到1的距离
举个例子:如w(1,2)=3 w(1,3)=4 那么必须满足w(2,3)>=4 否则从点将1,2,3连通的最小路径变为(1,2)(2,3)那么(1,3)就不会被选中,就违反我们之前的规定,又因为我们从小到大排序,并且先放生成树上的边,那么到当前边不在树上时,就可以直接放在之前已经放好的点上
如果已经放满,那么答案不存在

#include<bits/stdc++.h>
#define fi first
#define se second
#define log2(a) log(n)/log(2)
#define show(a) cout<<a<<endl;
#define show2(a,b) cout<<a<<" "<<b<<endl;
#define show3(a,b,c) cout<<a<<" "<<b<<" "<<c<<endl;
#define tim printf("Time cost : %lf s\n",(double)clock()/CLOCKS_PER_SEC);
using namespace std;
 
typedef long long ll;
typedef pair<int, int> P;
typedef pair<P, ll> LP;
const ll inf = 1e18;
const int N = 1e6 + 10;
const ll mod = 1e9 + 7;
const int base = 131;
const double pi = acos ( -1 );
const double eps = 1e-8;
inline ll ksm(ll a,ll b){ll ans=1;while(b){if(b&1)ans=ans*a%mod;a=a*a%mod,b>>=1;}return ans;}
 
 
ll  vis[N], num[N], n, m,  k, x, y, z;
ll a[N], b[N];
ll cx, cy, cnt, ans, sum, flag, t, ff;
 
//vector<int> v[N];
 
map<P, int> mp;
set<string> st;
P p[N];
char s[N];
ll dp[105][105];
 
struct node
{
	int w,k,id;
}no[N];
 
bool cmp(node a,node b)
{
	if(a.w==b.w) return a.k>b.k;
	return a.w<b.w;
}
int main()
{
	ios::sync_with_stdio ( false );
	cin.tie ( 0 );	cout.tie(0);
 
 
	cin>>n>>m;
	for(int i=1;i<=m;i++)
	{
		cin>>no[i].w>>no[i].k;
		no[i].id=i;
	}
	sort(no+1,no+m+1,cmp);
	cnt=1;
	k=1;
	int l=2,r=3;
 
	for(int i=1;i<=m;i++)
	{
 
		if(no[i].k)
		{
			cnt++;
			if(cnt>n) return cout<<-1,0;
			p[no[i].id].fi=1;p[no[i].id].se=cnt;
			num[cnt]=no[i].w;
 
 
		}
		else
		{
 
			if(r>cnt) return cout<<-1,0;
			//show3(no[i].id,no[i].w,r)
			p[no[i].id].fi=l;p[no[i].id].se=r;
			//show3(no[i].id,l,r)
			l++;
			if(l==r) r++,l=2;
		}
 
	}
	if(cnt!=n) return cout<<-1,0;
	//cout<<no[1].k<<endl;
 
	for(int i=1;i<=m;i++)
	{
		cout<<p[i].fi<<" "<<p[i].se<<endl;
	}
 
 
 
 
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值