• P5659 树上的数


    Aimee

    很恶心的一道题

    我们在考场上会遇到很多题,无论多难,都要大声喊出:"无所谓"。

    怎么无所谓,有所谓
    --scz

    10分做法

    爆搜

    #include<iostream>
    #include<cstdio> 
    #include<algorithm>
    #include<cstring>
    using namespace std;
    int n;
    int t;
    int head[2001];
    int zn[2001];
    int tem[2001];
    struct ed{
    	int f;
    	int to;
    	int ne;
    	int v;
    } e[2001];
    int p;
    int vis[2001];
    int ans[2001],now[2001];
    int x,y,z;
    void add(int f,int to){
    	p++;
    	e[p].f=f;
    	e[p].ne=head[f];
    	e[p].to=to;
    	return ;
    }
    void simex(){
    	for(int i=1;i<=n;++i){
    		ans[i]=tem[i];
    	}
    }
    void work(){
    	for(int i=1;i<=n;++i){
    		tem[zn[i]]=i;
    	}
    	for(int i=1;i<=n;++i){
    		now[i]=tem[i]; 
    	}
    	int f=0;
    	for(int i=1;i<=n;++i){
    		if(now[i]<ans[i]){
    			f=1;
    			simex();
    			break;
    		}else{
    			if(now[i]==ans[i])
    			continue;
    			break;
    		}
    	}
    	return ;
    }
    void dfs(int now){
    	if(now==n-1){
    		work();
    		return ;
    	}
    	for(int i=1;i<n;++i){
    		if(!vis[i]){
    			swap(zn[e[i].f],zn[e[i].to]);
    			vis[i]=now+1;
    			dfs(now+1);
    			vis[i]=0;
    			swap(zn[e[i].f],zn[e[i].to]);
    		}
    	}
    	return ;
    }
    int main(){
    	scanf("%d",&t);
    	while(t--){
    		p=0;
    		scanf("%d",&n);
    		for(int i=1;i<=n;++i){
    			scanf("%d",&x);
    			zn[x]=i;
    			head[i]=0;
    			ans[i]=0x7ffffff;
    		}
    		for(int i=1;i<n;++i){
    			scanf("%d%d",&x,&y);
    			add(x,y);
    		}
    		dfs(0);
    		for(int i=1;i<=n;++i){
    			cout<<ans[i]<<" ";
    		}
    		cout<<endl;
    	}
    	return 0;
    }
    

    我高考物理满分
    ---scz

    菊花图

          一个更绕的贪心
          #include<iostream>
    #include<cstdio> 
    #include<algorithm>
    #include<cstring>
    using namespace std;
    int n;
    int t;
    int head[2001];
    int zn[2001];
    int tem[2001];
    struct ed{
    	int f;
    	int to;
    	int ne;
    	int v;
    } e[2001];
    int p;
    int vis[2001];
    int ans[2001],now[2001];
    int du[2001];
    int fa[2001]; 
    int x,y,z;
    int Aimee;
    int put[2001];
    void add(int f,int to){
    	p++;
    	e[p].f=f;
    	du[x]++;
    	du[to]++;
    	Aimee=max(Aimee,max(du[x],du[to]));
    	e[p].ne=head[f];
    	e[p].to=to;
    	return ;
    }
    void simex(){
    	for(int i=1;i<=n;++i){
    		ans[i]=tem[i];
    	}
    }
    int find(int x){
    	return x==fa[x]? x:fa[x]=find(fa[x]);
    }
    void work(){
    	for(int i=1;i<=n;++i){
    		tem[zn[i]]=i;
    	}
    	for(int i=1;i<=n;++i){
    		now[i]=tem[i]; 
    	}
    	int f=0;
    	for(int i=1;i<=n;++i){
    		if(now[i]<ans[i]){
    			f=1;
    			simex();
    			break;
    		}else{
    			if(now[i]==ans[i])
    			continue;
    			break;
    		}
    	}
    	return ;
    }
    void dfs(int now){
    	if(now==n-1){
    		work();
    		return ;
    	}
    	for(int i=1;i<n;++i){
    		if(!vis[i]){
    			swap(zn[e[i].f],zn[e[i].to]);
    			vis[i]=now+1;
    			dfs(now+1);
    			vis[i]=0;
    			swap(zn[e[i].f],zn[e[i].to]);
    		}
    	}
    	return ;
    }
    void com(int x,int y){
    	fa[fa[find(x)]]=fa[find(y)];
    	return ;
    } 
    //花啊 
    void flower(){
    	for(int i=1;i<=n;++i){
    		fa[i]=i;
    		now[zn[i]]=i;
    		//now 意味着该数字所处的位置 
    		vis[i]=0;
    	}
    	for(int i=1;i<n;++i){
    		cout<<"i"<<i<<endl;
    		for(int j=1;j<=n;++j){
    			if(!vis[j]&&find(now[i])!=find(j)){
    				vis[j]=1;
    				put[now[i]]=j;
    				//那么,就应该把这个数字扔到j上去
    				//也就是put i的位置到j
    				//但是,因为这是个菊花图
    				//你把A扔到了B,那么B是不可能再回到A的
    				//因为是菊花图,用一个并查集解决
    				//就正如样例中的图
    				//1肯定不能留在1,那么最好的办法是把1送到2好点上,也是就put[now[1]]=2;
    				//那么这么搞 i号点的位置就会被放个 j
    				//交换了
    				 //同一个并查集是不能乱跑的 ,因为这是菊花图,既然在其之前没了,那么肯定是没路了
    				 //但是因为中间就一个节点,其他地方随便跑
    				 //只要还不在一个并查集, 那么肯定有路
    				 //而在一个并查集中,那这两个点肯定不能互相抵达了
    				 //也就是说对于菊花图,
    				 //用数字来决定点的顺序
    				 //但是由点来决定能不能跑  
    				 //要是两个点在同一个并查集里
    				 //那么这两个"点"之间的边肯定被走过了
    				 //所以说这个"数字"只能去别的点(并查集以外了)
    				 //所以说,这个点就是在确定可以往哪跑
    				 //毕竟倘若自己所在的 “点”已经被vis了,那么自己现在肯定处于这个并查集和其他自由区域的
    				 //交界处,也就是其他的随便走 
    				com(now[i],j);
    				 break;
    			}
    		}
    		cout<<"S";
    		for(int j=1;j<=n;++j){
    			cout<<vis[j]<<" ";
    		} 
    		cout<<endl;
    	}
    	for(int i=1;i<n;++i){
    		cout<<put[now[i]]<<" ";
    	}		
    	for(int i=1;i<=n;++i){
    		if(!vis[i]){
    			cout<<i<<endl;
    			break;
    		}
    	}		
    }
    int main(){
    	scanf("%d",&t);
    	while(t--){
    		p=0;
    		scanf("%d",&n);
    		Aimee=0;
    		for(int i=1;i<=n;++i){
    			scanf("%d",&x);
    			du[i]=0;
    			zn[x]=i;
    			head[i]=0;
    			ans[i]=0x7ffffff;
    		}
    		for(int i=1;i<n;++i){
    			scanf("%d%d",&x,&y);
    			add(x,y);
    		}
    			flower();
    	}
    	return 0;
    }
    


    这东西没有啥额外的思维难度

    主要就是贪心的想法

    对于每一个点,送到可行的最小编号的点上,那么问题不大

    就是会得到一个边的删除先后问题的问题

    ??先后,拓扑排序检查是否合法

    那就没有代码了。

    100pts

    思路很好想?细节恶心

    参考了此位大佬

    #include<iostream>
    #include<cstdio> 
    #include<algorithm>
    #include<cstring>
    #define int long long
    using namespace std;
    int n;
    int t;
    int head[2501];
    int zn[2005];
    int tem[2051];
    struct ed{
    	int f;
    	int to;
    	int ne;
    	int v;
    } e[(2000<<1)+5];
    int p;
    int fa[2051]; 
    int siz[2501];
    int x,y,z;
    int len[2505][2005],pre[2005][2005],nex[2005][2005],rt[2005][2005][2]; 
    int put[2005];
    int Aimee;
    void add(int f, int to){
    	siz[f]++;
    	siz[to]++;
    	e[++p].ne=head[f];
    	e[p].to=to;
    	head[f]=p;
    	e[++p].ne=head[to];
    	e[p].to=f;
    	head[to]=p;
    	return ;
    }
    void begin(){
    	for(int i=1;i<=n+1;++i){
    		for(int j=1;j<=n+1;++j)
    		len[i][j]=nex[i][j]=pre[i][j]=rt[i][j][0]=rt[i][j][1]=0;
    	}
    	for(int i=1;i<n;++i){
    		scanf("%d%d",&x,&y);
    		add(x,y);
    		rt[x][y][0]=rt[x][y][1]=y;
    		rt[y][x][0]=rt[y][x][1]=x;
    		len[x][y]=len[y][x]=1;
    	}
    }
    void find(int now,int la){
    	int l=rt[now][la][0],r=rt[now][la][1],ll,rr;
    	int v;
    	if(la==n+1){
    		for(int i=head[now];i;i=e[i].ne){
    			v=e[i].to;
    			ll=rt[now][v][0],rr=rt[now][v][1];
    			if(ll!=v||(pre[now][la]==rr&&len[now][ll]<siz[now]))
    			continue;
    			find(v,now);
    		}
    	}else{
    		if(la==r){
    			if(pre[now][n+1]==0&&(nex[now][n+1]!=l||len[now][l]==siz[now]))
    			Aimee=min(Aimee,now);
    			for(int i=head[now];i;i=e[i].ne){
    				v=e[i].to;
    				ll=rt[now][v][0],rr=rt[now][v][1];
    				if(l==ll||ll!=v||nex[now][n+1]==v)
    				continue;
    				if(nex[now][n+1]==l&&pre[now][n+1]==rr&&len[now][l]+len[now][ll]<siz[now]){
    					continue;
    				}
    				find(v,now);
    			}
    		}
    		else find(nex[now][la],now);
    	}
    }
    void com(int now,int h,int t){
    	int ll=rt[now][h][0],rr=rt[now][t][1];
    	nex[now][h]=t;
    	pre[now][t]=h;
    	for(int i=ll;i&&i!=n+1;i=nex[now][i]){
    		rt[now][i][0]=ll;
    		rt[now][i][1]=rr;
    	}
    	len[now][ll]+=len[now][t];
    }
    bool mark(int now,int la){
    	if(now==Aimee){
    		pre[now][n+1]=la;
    		nex[now][la]=n+1;
    		return 1;
    	}
    	int v;
    	int l=rt[now][la][0],r=rt[now][la][1],ll,rr;
    	if(la==n+1){
    		for(int i=head[now];i;i=e[i].ne){
    			v=e[i].to;
    			ll=rt[now][v][0],rr=rt[now][v][1];
    			if(ll!=v||(pre[now][la]==rr&&len[now][ll]<siz[now]))
    			continue;
    			if(mark(v,now)){
    				nex[now][n+1]=v;
    				pre[now][v]=n+1;
    				return 1;
    			}
    		}
    	}else{
    		if(la==r){
    			for(int i=head[now];i;i=e[i].ne){
    				v=e[i].to;
    				ll=rt[now][v][0],rr=rt[now][v][1];
    				if(l==ll||ll!=v||nex[now][n+1]==v)
    				continue;
    				if(nex[now][n+1]==l&&pre[now][n+1]==rr&&len[now][l]+len[now][ll]<siz[now]){
    					continue;
    				}
    				if(mark(v,now)){
    					com(now,la,v);
    					return 1;
    				}
    			}
    		}else
    		mark(nex[now][la],now) ;
    	}
    } 
    signed main(){
    	scanf("%d",&t);
    	while(t--){
    		p=0;
    		scanf("%d",&n);
    		for(int i=1;i<=n;++i){
    			scanf("%d",&zn[i]);
    			siz[i]=0;		
    			head[i]=0;
    		}
    		begin();
    		if(n==1){
    			cout<<1<<endl;
    			continue;
    		}
    		for(int i=1;i<=n;++i){
    			Aimee=n+1;
    			find(zn[i],n+1);
    			mark(zn[i],n+1);
    			cout<<Aimee<<" "; 
    		}
    		cout<<endl;
    	}
    	return 0;
    }
    
  • 相关阅读:
    阶梯博弈
    hihoCoder #1199 : Tower Defense Game ——(树型dp)
    2016 China-Final-F题 ——(SA+二分)
    ACM之路(20)—— Splay初探
    2016 ICPC China-Final 现场赛总结
    【Interleaving String】cpp
    【Best Time to Buy and Sell Stock III 】cpp
    【Maximal Rectangle】cpp
    【palindrome partitioning II】cpp
    【Maximum Subarray 】cpp
  • 原文地址:https://www.cnblogs.com/For-Miku/p/13893211.html
Copyright © 2020-2023  润新知