https://www.luogu.com.cn/problem/CF566E
感觉浪费了一道好题,没有好好分析性质
若非叶子节点有连边,则存在两个集合的交集为 { x , y } \{x,y\} {x,y}
然后就可以区分叶子和非叶子节点
对于叶子节点,包含它大小最小的集合就是对应的集合。
对于非叶只计算<=1距离的点,设为 G G G
显然在非叶>=3时 G G G 互不相同。
对于叶子节点集合取掉叶子节点结合后唯一对应的 G G G 就是自己的父亲
发现上述过程可以bitset优化
#include
using namespace std;
//#define int long long
inline int read(){int x=0,f=1;char ch=getchar(); while(ch<'0'||
ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){
x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f;}
#define Z(x) (x)*(x)
#define pb push_back
//mt19937 rand(time(0));
//mt19937_64 rand(time(0));
//srand(time(0));
#define N 1010
//#define M
//#define mo
int n, m, i, j, k, T;
vector<pair<int, int> >ans;
map<pair<int, int>, int>mp;
//bitset<10>S, G[N], t, s[N];
bitset<N>S, G[N], t, s[N];
int p[N], c[N], mn, x, y;
int f[N];
void sol1() {
for(i=2; i<=n; ++i) printf("1 %d\n", i);
}
void sol2() {
S=t=0;
for(i=1; i<=n; ++i) {
if(!p[i]) continue;
k=f[i];
if(S.count()==0 || s[k]==S) ans.pb({x, i}), S=s[k];
else ans.pb({y, i}), t=s[k];
}
for(auto t : ans) printf("%d %d\n", t.first, t.second);
}
signed main()
{
// freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
// T=read();
// while(T--) {
//
// }
n=read(); mn=1e9;
if(n==2) return printf("1 2\n"), 0;
for(i=1; i<=n; ++i) {
p[i]=1;
c[i]=read(); mn=min(mn, c[i]);
for(j=1; j<=c[i]; ++j) {
k=read(); s[i][k]=1;
}
// cout<
}
if(mn==n) return sol1(), 0;
for(i=1, k=0; i<=n; ++i)
for(j=i+1; j<=n; ++j) {
S=(s[i]&s[j]);
if(S.count()!=2) continue;
x=S._Find_first(); y=S._Find_next(x);
p[x]=p[y]=0; // they are not leaf
if(!mp[{x, y}]) ans.pb({x, y}), ++k;
mp[{x, y}]=1;
G[x][y]=G[y][x]=G[x][x]=G[y][y]=1;
}
// for(i=1; i<=n; ++i)
// for(j=1; j<=n; ++j)
// if(i!=j && (s[i]|s[j])==s[j]) ans.pb({i, j});
// for(i=1; i<=n; ++i) cout<
S=0; //叶子节点的集合
for(i=1; i<=n; ++i) if(p[i]) S[i]=1;
// printf("S : \n"); cout<
for(i=1; i<=n; ++i) if(p[i]) {
mn=1e9;
for(j=1; j<=n; ++j)
if(s[j][i] && s[j].count()<mn) f[i]=j, mn=s[j].count();
}
if(k==1) return sol2(), 0;
for(i=1; i<=n; ++i) if(p[i]) {
k=f[i]; t=(S&s[k]);
t=(s[k]^t);
// printf(">> %d : %d ", i, k); cout<
for(j=1; j<=n; ++j) if(G[j]==t) ans.pb({j, i});
}
for(auto t : ans) printf("%d %d\n", t.first, t.second);
return 0;
}