题意
给出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;
}
}