Foul Play(决策+递归)

A European soccer tournament has n participating teams. In the first round, n/2 matches are played
such that each team plays against one other team. After every round, only the winning teams advance
to the next round. In the second round, n/4 matches are played such that each first-round winner plays
against one other first-round winner. Eventually, only two teams are left to play a final match. The
winner of the final match is the champion of the tournament.
The Dutch soccer team is probably not the best team in the world. However, they are still a pretty
good team. They can easily win from at least half of the other teams. Moreover, for every team t that
the Dutch cannot beat in a direct confrontation, there is another team t

that beats t, but is beaten by
the Dutch team.
The Dutch coach wants to manipulate the tournament such that the Dutch team will become
champion. He happens to know, for each pair of teams, which team would certainly win if a match was
played between them.
Problem
For each two teams, you know beforehand which one would win if they played against each other.
(Since this is a knock-out tournament, no ties will occur.) Furthermore, you know for sure that your
favourite team can beat at least half of the other teams, and for every team t that your favourite team
cannot beat, there is a team t

that beats t but is itself beaten by your favourite team.
Determine a tournament schedule such that your favourite team wins the tournament.
Input
For each test case, the input is as follows:
• One line containing the number of teams n, where n is a power of two and 2 ≤ n ≤ 1024. Teams
are numbered from 1 to n, where team 1 is your favourite team.
• n lines, each containing a string of n binary digits.
The k-th digit on the j-th line is ‘1’ if team j would certainly win from team k, otherwise it is
‘0’.
A team cannot play against itself, therefore the j-th digit on the j-th line is ‘0’.
If j ̸= k, the k-th digit on the j-th line is different from the j-th digit on the k-th line.
Output
For each test case, print n − 1 lines of output, specifying a tournament schedule that ensures victory
for team 1.
The first n/2 lines describe the first round of the tournament. The next n/4 lines describe the
second round, if any, etc. The last line describes the final match.
Each line contains two integers x and y, indicating that team x plays a match against team y.
If there are multiple tournament schedules where team 1 wins, any one of those tournament schedules
will be accepted as a correct answer.
Sample Input
4
0110
0011
0000
1010
8
00111010
10101111
00010010
01000101
00110010
10101011
00010000
10101010
Sample Output
1 3
2 4
1 2
1 5
3 7
4 8
2 6
1 3
4 2
1 4
题意:有n支队伍,你支持第一支队伍,已知第一支队伍至少赢一半以上的队伍,给出每个队伍与其他队伍的实力对比(一定赢或一定输)问每轮的对战安排,使得第一支队伍获得冠军。
我一开始看的时候以为一旦底层确定了,那么上面也确定了,按照这个顺序输出,想了半天,只能dfs搜一遍(明知道会T)……

#include<cstdio>
#include<cstring>
#include<iostream>
#include<queue>
#include<vector>
#include<algorithm>
#include<string>
#include<cmath>
#include<set>
#include<map>
#include<vector>
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int maxn = 1005;
char a[1050];
vector<int>vt[1050];
int ans[7200], n;
bool leap[1050];
bool dfs(int start, int level, int up)
{
    if (up == n * 4)return true;
    int u = ans[start];
    int i;
    for (i = 0; i < vt[u].size(); i++)
    {
        int v = vt[u][i];
        if (!leap[v])continue;
        if (vt[v].size() < level - 1)continue;
        leap[v] = false;
        ans[start + 1] = v;
        ans[2 * start] = u;
        ans[2 * start + 2] = v;
        if (start == up - 2 && dfs(start + 2, level - 1, up * 2))break;
        else if (dfs(start + 2, level, up))break;
        else leap[v] = true;
    }
    if (i == vt[u].size())return false;
    return true;
}
int main()
{
#ifdef LOCAL
    freopen("C:\\Users\\ΡΡ\\Desktop\\in.txt", "r", stdin);
    //freopen("C:\\Users\\ΡΡ\\Desktop\\out.txt","w",stdout);
#endif // LOCAL
    while (scanf("%d", &n) != EOF)
    {
        for (int i = 1; i <= n; i++)vt[i].clear();
        for (int i = 1; i <= n; i++)
        {
            scanf("%s", a);
            for (int j = 0; j < n; j++)
            {
                if (i - 1 == j)continue;
                if (a[j] == '1')
                    vt[i].push_back(j + 1);
            }
        }
        int level = 0;
        int num = n;
        while (num != 0)
        {
            num = num / 2; level++;
        }
        for (int i = 1; i <= n; i++)leap[i] = true;
        ans[1] = ans[2] = 1;
        leap[1] = false;
        dfs(2, level - 1, 4);
        for(int i = n*2 - 1;i > 1;i = i - 2)
        {
            printf("%d %d\n",ans[i - 1],ans[i]);
        }
    }
    return 0;
}

然后就是汝佳的想法了= =,首先大前提是,只需要按轮输出比赛场次就行了,和前一轮没有任何关系。
1,题目保证,1打不过的,一定有一个队打不过1,但是打过这只队伍,定义打不过1的是灰色,打得过1的是黑色;
2,接着,所有黑色队伍找其对应的灰色队伍并且灰色队伍没被安排比赛,这样这些黑队就被消灭了;
3,找一只灰色队伍给1,1一定胜利;
4,黑色自己打自己;
5,剩下的队伍混在一起打。

假设到最后剩下一只黑色队伍,那么在这n轮比赛中,他一定会遇到那个比他强的灰色队伍。
在一一对应时候没遇到,只能说明这只灰色队伍和其他黑色打,那么这支灰色队伍也晋级到下一轮;
在n轮比赛中,一定会遇到这只灰色队伍,因此不存在这样的黑色队伍,假设不存在。

按照这个实现,我写的相当丑==

#include<cstdio>
#include<cstring>
#include<iostream>
#include<queue>
#include<vector>
#include<algorithm>
#include<string>
#include<cmath>
#include<set>
#include<map>
#include<vector>
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int maxn = 1005;
char a[1050];
int ans[10050],n,cnt;
bool mp[1050][1050],leap[1050];
void dfs(int start,int num)
{
    if(num == 1)return;
    for(int i = 2;i <= n;i++)
    {
        if(!leap[i] || mp[1][i])continue;
        for(int j = 2;j <= n;j++)
        {
            if(i == j)continue;
            if(!leap[j])continue;
            if(!mp[1][j])continue;
            if(mp[j][i])
            {
                ans[cnt++] = j;
                ans[cnt++] = i;
                leap[i] = leap[j] = false;
                break;
            }
        }
    }
    for(int i = 2;i <= n;i++)
    {
        if(leap[i]&&mp[1][i])
        {
            ans[cnt++] = 1;
            ans[cnt++] = i;
            leap[i] = false;
            break;
        }
    }
    for(int i = 2;i <= n;i++)
    {
        if(leap[i]&&!mp[1][i])
        {
            for(int j = 2;j <= n;j++)
            {
                if(leap[j]&&!mp[1][j]&&i != j)
                {
                    if(mp[i][j])
                    {
                        ans[cnt++] = i;
                        ans[cnt++] = j;
                        leap [i] = leap[j] = false;
                        break;
                    }
                    else
                    {
                        ans[cnt++] = j;
                        ans[cnt++] = i;
                        leap[i] = leap[j] = false;
                        break;
                    }
                }
            }
        }
    }
    for(int i = 2;i <= n;i++)
    {
        if(leap[i])
        {
            for(int j = 2;j <= n;j++)
            {
                if(leap[j]&&i != j)
                {
                    if(mp[i][j])
                    {
                        ans[cnt++] = i;
                        ans[cnt++] = j;
                        leap[i] = leap[j] = false;
                        break;
                    }
                    else
                    {
                        ans[cnt++] = j;
                        ans[cnt++] = i;
                        leap[i] = leap[j] = false;
                        break;
                    }
                }
            }
        }
    }
    for(int i = cnt - num;i < cnt;i = i + 2)
    {
        int e = ans[i];
        if(e != 1)
            leap[e] = true;
    }
    dfs(start + num,num/2);
}
int main()
{
#ifdef LOCAL
    freopen("C:\\Users\\ΡΡ\\Desktop\\in.txt", "r", stdin);
    //freopen("C:\\Users\\ΡΡ\\Desktop\\out.txt","w",stdout);
#endif // LOCAL
    while (scanf("%d", &n) != EOF)
    {
        memset(mp,0,sizeof(mp));
        for (int i = 1; i <= n; i++)
        {
            scanf("%s", a);
            for (int j = 0; j < n; j++)
            {
                if (i - 1 == j)continue;
                if (a[j] == '1')
                    mp[i][j + 1] = 1;
            }
        }
        for(int i = 1;i <= n;i++)leap[i] = true;
        leap[1] = false;
        cnt = 1;
        dfs(1,n);
        for(int i = 1;i < n;i++)
        {
            printf("%d %d\n",ans[2*i - 1],ans[2*i]);
        }
    }
    return 0;
}
### YOLO中的Focal CIoU损失函数 在YOLO系列的目标检测算法中,为了提升边界框回归的准确性并处理类别不平衡问题,引入了多种改进型损失函数。其中一种组合方式是将Focal Loss与CIoU (Complete Intersection over Union) 结合起来形成所谓的 **Focal CIoU** 损失函数。 #### Focal CIoU损失函数的作用 该损失函数不仅能够有效减少正负样本之间的数量差异带来的影响,还能更精确地衡量预测框和真实框之间位置关系的质量[^3]。具体来说: - **Focal Loss部分**: 主要用于解决前景背景极度不均衡的问题,通过调整难易分类样本权重来改善模型学习效果; - **CIoU部分**: 则专注于提高边框回归质量,相比传统的IoU或GIoU, CIoU考虑到了更多几何特性因素如中心点距离以及宽高比例等因素的影响; 两者结合可以更好地服务于目标检测任务,在保持较高召回率的同时降低误检概率。 #### 实现代码示例 以下是基于PyTorch框架下实现的一个简单版`focal_ciou_loss()` 函数: ```python import torch from torchvision.ops import box_iou def focal_ciou_loss(pred_boxes, target_boxes, alpha=0.25, gamma=2.0): """ 计算Focal CIoU损失 参数: pred_boxes: 预测框坐标 Tensor[N, 4], xyxy格式 target_boxes: 真实框坐标 Tensor[N, 4], xyxy格式 alpha: Focal loss 的alpha参数,默认为0.25 gamma: Focal loss 的gamma参数,默认为2 返回: float: 平均后的总损失值 """ # 获取iou矩阵 ious = box_iou(pred_boxes, target_boxes).diag() # 计算ciou cious = compute_ciou(pred_boxes, target_boxes) # 计算focal factor p_t = ious * ((target_boxes[:, None]).eq(1)).float().sum(dim=-1) modulating_factor = (p_t / (1 - p_t + 1e-8)) ** gamma weighting_factor = alpha * target_boxes.new_ones(target_boxes.size()) + \ (1-alpha)*((pred_boxes[:,None]-target_boxes)**2).mean(-1).sqrt() # 综合计算最终loss final_loss = -(weighting_factor * modulating_factor * torch.log(cious.clamp(min=1e-9))).mean() return final_loss def compute_ciou(bboxes1, bboxes2): """Compute the CIOU of two sets of boxes.""" rows = bboxes1.shape[0] cols = bboxes2.shape[0] center_x1 = (bboxes1[..., 0] + bboxes1[..., 2]) / 2. center_y1 = (bboxes1[..., 1] + bboxes1[..., 3]) / 2. center_x2 = (bboxes2[..., 0] + bboxes2[..., 2]) / 2. center_y2 = (bboxes2[..., 1] + bboxes2[..., 3]) / 2. inter_max_xy = torch.min(bboxes1[:, 2:], bboxes2[:, 2:]) inter_min_xy = torch.max(bboxes1[:, :2], bboxes2[:, :2]) out_max_xy = torch.max(bboxes1[:, 2:], bboxes2[:, 2:]) out_min_xy = torch.min(bboxes1[:, :2], bboxes2[:, :2]) inter = torch.clamp((inter_max_xy - inter_min_xy), min=0) inter_area = inter[:, 0] * inter[:, 1] inter_diag = (center_x2 - center_x1) ** 2 + (center_y2 - center_y1) ** 2 outer = torch.clamp((out_max_xy - out_min_xy), min=0) outer_diagonal = (outer[:, 0] ** 2) + (outer[:, 1] ** 2) union = area1 + area2 - inter_area u = (inter_diag) / outer_diagonal w1 = bboxes1[..., 2] - bboxes1[..., 0] h1 = bboxes1[..., 3] - bboxes1[..., 1] w2 = bboxes2[..., 2] - bboxes2[..., 0] h2 = bboxes2[..., 3] - bboxes2[..., 1] v = (4 / math.pi ** 2) * torch.pow( torch.atan(w2 / h2) - torch.atan(w1 / h1), 2 ) with torch.no_grad(): S = 1 - inter_area / union alpha = v / (S + v) ciou_term = v * alpha ciou = iou - u - ciou_term return ciou.mean() if __name__ == '__main__': pass ``` 此段代码实现了针对给定的真实标签框(`target_boxes`)及其对应的预测框(`pred_boxes`)计算其间的平均Focal CIoU损失。注意这里简化了一些细节以便理解核心逻辑[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值