zoukankan      html  css  js  c++  java
  • CF 566E Restoring Map

    在WC时,jmr在他的《集训队作业选作》中给出了这个题的精确解答
    这算是我为数不多听明白的题目了
    人生中第一道黑题!!!

    思路

    因为题目中并没有将集合与点的对应关系告诉我们
    所以相当于已知一个大集合,其中下辖着各个小集合,小集合中涵盖着点
    这就引导着我们朝着集合的角度来思考答案

    在我们还没有分析题目之前,先做几个简单但重要的事,这是之后证明的前提

    1 判菊花图
    2 特判n=2或3

    (f_u)(u)的距离(≤2)的集合
    首先可以分析出当两个点的距离大于4时,没有所在集合没有交点
    当距离等于4时,可以判出一个点(但这并没有什么用)
    当距离等于3时,可以判出两个节点,并且均不为叶节点
    小于2时,我们发现似乎讨论不太出更多性质(3就够了

    据此我们可以将一棵树中的所有非叶节点都筛出来,将该集合记为(releaf),我们可以知该集合中任意元素均为非叶节点,接下来我们证明其必要性

    (prove):

    假设我们已经充分的对集合两两求交,(releaf)已经完善
    设存在一个非叶节点(u)(s.t.) (u otin releaf)(u)必然存在一条边(E),在(E)上另一点(vin releaf)因为(v,u)非叶节点,那么对其子节点进行集合求交,则可以筛出(u,v),但(releaf)并不存在(u,v),所以假设不成立

    现在我们已有(releaf),非常自然地将这个题转化为向(releaf)中的点挂叶节点,并且我们可以建出(releaf)树,借助这个树,我们可以处理与树中点(u)距离(≤1)的点集(g_u),然后我们可以发现一个点(v)可以挂在(u)上,那么其满足(g_u)(=)(f_v and releaf)
    但是我们又遇到了一个问题,如果(vin releaf),那么也满足上式,为了解决这个问题,我们决定研究一下怎么判出集合与点的对应关系

    先给出结论:
    对于一个叶节点 x,包含 x 的(f_x)中元素个数最小的(f)就是 x 的(f_x)

    我不打算证明了
    算法复杂度(O(frac{n^3}{w} ))

    (detail)

    算法中(bitset)中寻找(1)不能使用(for)循环,若使用复杂度不会除(w)
    所以使用(\_ Find \_ first)(\_ Find \_ next)
    前者是找第一个1,后者是找下一个1

    Code

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<bitset> 
    #include<set>
    
    using namespace std;
    
    #define fx(x) _Find_next(x)
    #define ff() _Find_first() 
    #define int long long
    #define INF 1<<30
    
    const int p=1e3+5;
    
    template<typename _T>
    inline void read(_T &x)
    {
    	x=0;char s=getchar();int f=1;
    	while(s<'0'||s>'9') {f=1;if(s=='-')f=-1;s=getchar();}
    	while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+s-'0';s=getchar();}
    	x*=f;
    }
    
    bitset<p> b[p];
    bitset<p> g[p];
    bitset<p> ans[p];
    bitset<p> releaf;
    int tit;
    int a[p];
    int vis[p];
    bool c[p][p];
    bitset<p> lef,rig;
    
    signed  main()
    {
    	int n;
    	read(n);
    	
    	if(n == 2){cout<<1<<" "<<2;return 0;}
    	if(n == 3){cout<<1<<" "<<2<<'
    '<<2<<" "<<3<<'
    ';return 0;}
    	
    	for(int i=1,x;i<=n;i++)
    	{
    		read(x);
    		for(int j=1,y;j<=x;j++)
    		{
    			read(y);
    			b[i].set(y-1);
    		}
    	}
    	releaf = b[1];
    	for(int i=2;i<=n;i++) releaf&=b[i];
    	if(releaf.count() == n){
    		for(int i=2;i<=n;i++)
    		{
    			cout<<1<<" "<<i<<'
    ';
    		}
    		return 0;
    	}
    	releaf.reset();
    	bitset<p> op;
    	for(int i=1;i<=n;i++)
    		for(int j=1;j<=n;j++)
    		{
    			if(i == j) continue;
    			op = b[i]&b[j];
    			int x = op._Find_first();
    			int y = op._Find_next(x);
    			
    			if(op.count()==2)
    			{
    				g[x+1].set(y);
    				g[x+1].set(x);
    				g[y+1].set(x);
    				g[y+1].set(y);		
    				releaf|=op;
    			}
    		}
    	int len = releaf.size();
    	bitset<p> ks;
    	if(releaf.count()==2) 
    	{
    		for(int i=1;i<=n;i++)
    		{
    			if(b[i].count()!=n)
    			{
    				lef |= b[i];
    				lef ^=releaf;
    				break;	
    			}
    		}
    		
    		int st = releaf.ff();
    		int ry = releaf.size();
    		int stt = releaf.fx(st);
    		cout<<st+1<<" "<<stt+1<<'
    ';
    		for(int i=0;i<n;i++)
    		{
    			if(lef[i]) cout<<st+1<<" "<<i+1<<'
    ';
    			else 
    			{
    				if(i!=st&&i!=stt)
    				{
    					cout<<stt+1<<" "<<i+1<<'
    ';
    				}
    			}
    		}
    		return 0;
    	}
    	for(int i=0;i<len;i++)
    	{
    		ks.reset();ks.set(i);
    		ks = ks&releaf;
    		if(ks.count()) a[++tit] = i+1;
    	}
    	
    	bitset<p> aux;
    	aux = releaf;
    	aux.flip();	
    	int opt  = aux.ff();
    	int gi = -1;
    	for(;opt!=gi&&opt<n;opt = aux.fx(opt))
    	{
    		int minn = INF;
    		int lsq= 0 ;
    		for(int i=1;i<=n;i++) 
    		{
    			int ikj = 0;
    			if(b[i][opt])
    			{
    				if(minn>(b[i]&releaf).count())
    				{
    					ikj =1;
    					ks = b[i]&releaf;
    					minn = ks.count();
    					vis[opt+1] = i;
    				}
    			}
    		}		
    		for(int j=1;j<=tit;j++)
    		{
    			if(g[a[j]] == ks)
    			cout<<a[j]<<" "<<opt+1<<'
    ';
    		}		
    		gi = opt;
    	}
    	for(int i=1;i<=tit;i++)
    	{
    		g[a[i]][a[i]-1] = 0;
    		gi =- 1;
    		opt = g[a[i]].ff();
    		for(;opt!=gi&&opt<n;opt = g[a[i]].fx(opt))
    		{
    			if((!c[a[i]][opt+1])&&(!c[opt+1][a[i]]))
    			{
    				cout<<a[i]<<" "<<opt+1<<'
    ';
    				c[a[i]][opt+1] = c[opt+1][a[i]] = 1;
    			}
    			gi = opt;
    		}
    	}
    	
     }
    

    (End)

    这是我的第一道黑题,也是第一道(bitset)优化构造题

  • 相关阅读:
    HPUX巡检
    关于一些pdf撞的南墙(.net)
    Spire pdf 操作pdf,页眉 页脚 水印 二维码
    生成的excel转成Pdf(接上篇)
    NPOI操作excel--以及组件转换成Pdf
    以下代码输出啥?为什么会这样输出?
    转:data-toggle与data-target的作用
    告别外包,重新出发
    AutoFac依赖注入框架--个人测试demo-新手
    C# json转xml
  • 原文地址:https://www.cnblogs.com/-Iris-/p/14368170.html
Copyright © 2011-2022 走看看