L2-047 锦标赛

L2-047锦标赛

解题思路

首先输入的是k,代表游戏一共进行的轮数,然后接下来的k行,每行给出每轮中各个比赛的失败者。

最后一行给出冠军。

这个过程就是淘汰赛,像那个口袋妖怪绿宝石对战帐篷那个图一样,显然我们这里可以发现,这是一个树结构,并且是一个完全二叉树(这里表述可能不太准确,我是想表达每场比赛的胜者进入父节点的意思)。对于一个完全二叉树,其最突出的性质就是对于每个结点i,其子节点下标为 2×i 与 2×i+1 。而且这里还是一个大根堆。

本题最后一定是要建树的

然而这里的建树并没有什么规律(模拟一下就知道),只能采用暴力枚举的方法,如果最后枚举有一个解成立(成功建且符合大根堆),就直接结束dfs函数并准备输出。

dfs函数的过程是:由上到下,只有最后一轮的比赛是已知的,而最后一轮比赛的两个选手可以往下填,(这里是把每场比赛看成一个结点,但是每个节点存有胜者和败者,可以采用结构体),结构是这样的

//u是根节点
//只需要把父结点的两个人分配给子节点的赢家
tree[2*u].w = tree[u].w;
tree[2*u+1].w = tree[u].l;
//由于有左右两个子树,都要深搜一下。
if(dfs(2*u,size) && dfs(2*u+1,size)) return true;
//这只是一种情况,显然这里要回溯一下然后进行另一种情况的dfs
swap(tree[2*u].w,tree[2*u+1].w);
if(dfs(2*u,size) && dfs(2*u+1,size)) return true;

我寻思🤔写题解的时候六得很,实战的时候一个都写不对,不过这里的dfs函数本身确实不难,是最简单的那种

FB70319368DD30C13F9483A285F0CD01

然后是这题输入输出的问题(也是一个难点)

首先总结点数是 (\(2^k - 1\)) 个,输入的时候是从最后一层开始输入

for(int i = k-1 ; i >= 0 ; i-- )
{
	int st = 1 << i;
	int ed = 1 << (i+1);
	for(int j = st ; j < ed ; j ++)
	{
		cin>>tree[j].l;
	}
}

然后是输出,最后只需要输出最后一层,每个结点的输赢者

int st = 1 << (k-1);
int ed = 1 << k;
for(int i = st ; i < ed ; i++)
{
cout<<tree[i].w<<" "<<tree[i].l;
if(i != ed - 1) cout<<" ";
}

ac✅️代码

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;

const int N = 1 << 20;

struct Node
{
	int w,l;
}nodes[N];

int k;

bool dfs(int u, int size)//dfs的作用是看这条路行不行
{
	if(u > size) return true;//结束条件
	
	if(nodes[u].l > nodes[u].w) return false;//剪枝
	
	//接下来有两种选择,第一种是:胜者给左子树,败者给右子树
	nodes[2 * u].w = nodes[u].w;
	nodes[2 * u + 1].w = nodes[u].l;
	if(dfs(2 * u , size) && dfs(2 * u + 1 ,size)) return true;
	//如果第一种行不通,再选第二种,交换一下
	swap(nodes[2 * u].w , nodes[2 * u + 1].w);
	if(dfs(2 * u , size) && dfs(2 * u + 1 , size)) return true;
	//如果都不行,就返回false
	return false;
	
}
int main()
{
	if(!(cin>>k)) return 0;
    for(int i = k-1 ; i >= 0 ; i-- )
    {
	    int st = 1 << i;
	    int ed = 1 << (i+1);
	    for(int j = st ; j < ed ; j ++)
	    {
	    	cin>>nodes[j].l;
	    }
    }
	
	cin>>nodes[1].w;//还需要输入一个赢家
	
	int treesize = (1 << k) - 1;//数的大小
	
	if(dfs(1,treesize))
	{
		//由于每2个人绑定为一个节点,所以最后的节点数只有一半
		//编号为2^(k-1)到2^k - 1
        int st = 1 << (k-1);
        int ed = 1 << k;
        for(int i = st ; i < ed ; i++)
        {
            cout<<nodes[i].w<<" "<<nodes[i].l;
            if(i != ed - 1) cout<<" ";
        }
		cout<<endl;
	}
	else cout<<"No Solution"<<endl;
	return 0;
}
posted @ 2026-03-20 20:33  shuiwangrenjia  阅读(162)  评论(0)    收藏  举报