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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值