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;
}
原文地址:https://www.cnblogs.com/For-Miku/p/13893211.html