POJ-2699-玄学网络流-The Maximum Number of Strong Kings

(有任何问题欢迎留言或私聊 && 欢迎交流讨论哦

题目:传送门

 原题目描述及样例在最下面

 每次输入给你一行数字,代表n个人的得分。因为n个人之间一共会进行n*(n-1)/2场比赛。每场比赛必有胜负,胜者得一分。然后输入的得分保证非递减。

 问最多有多少人赢了所有得分比自己高的人。规定得分最高的那个人算符合条件。这种人称作king。

思路:

 居然使用最大流写。。。评论区有人贪心写的,好像是有问题的。然后这题好像可以二进制枚举写,因为n最大为10。

 但是你搞懂了之后,这题完全可以最大流写。二进制枚举是没有必要的。看了大神博客之后似懂非懂。觉得应该写个博客日后温故知新。

 先随手建个图:

 超级源点S向n个选手连边,流量为选手的赢得次数。m (=n*(n-1)/2) 场比赛向超级汇点T连边,流量为1,因为每场比赛只有一个人胜利。
 因为具体不知道那个选手赢了那场比赛,所以每个选手都向自己参加的比赛连一条边,流量为1。记得实现给比赛标号。

 这样建出来的图跑的最大流一定是n*(n-1)/2,也就是选手得分之和。下面再来考虑如何确定king的数量。

 有一个结论:

如果king的数量是k,则一定存在一种情况。得分最高的k个人是king。注意是存在,不是一定。

 先来讲如何根据这个结论建图,后面解释。

有了上面的结论就考虑从n到1枚举k。和初始图的区别在于如何处理选手和比赛间的边。

因为知道最后k个人会是king。
所以关于在最后k个人里,他们与所有得分比自己高的人间的比赛集合H:
他们向H连边,流量为1。比他们得分高的人不向这些比赛连边。因为我们知道得分高的人输了这些比赛。这是已知比赛结果的。

当然最后k个人中会有同分的情况,同分的话可能是a赢也可能是b赢,但不管谁赢,并不影响结果,仍有k个king。

所以最后k个人中同分的人都向他们间的比赛连边。

 就这样跑最大流,如果最大流等于n*(n-1)/2,则代表k个人是符合的。
 因为只有最大流等于所有比赛的场次,才代表所有比赛没有冲突,每个人的得分都得到了满足。

所以,为什么呢?

有这么种情况1…j…k…,其中 j 是king,k不是king。我们想把k变成king。
假设k在k+1到n个人间输了x场,那么j肯定赢了这x场。我们让k输的这x场变成赢的,让k在1到k-1中再输x场。
为了让k+1到n中的x场比分平衡,让j赢的变成输的。让j去赢1到k-1中x场(本来是k赢的x场,前面让这k输了这x场)。

要满足上述要求,只有k在1-到k-1中赢了x场的对手本来是输给了 j 的呢?
为什么肯定存在呢?因为k的比分大于等于j,k不是king而j是king。k在k+1到n间比j多输x场,那么k一定在1到j-1间比j多赢x场。
一定要仔细思考啊!!

AC代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int MAXN = 1e3+5;
const int INF = 0x3f3f3f3f;
typedef long long LL;
struct lp{
    int to,nex,cap,flow;
}cw[MAXN*10];
int tol;
int head[MAXN];
int gap[MAXN],dep[MAXN],pre[MAXN],cur[MAXN];
int n,m;
int ar[MAXN],mp[MAXN][MAXN];
char tools[100000];
void init(){
    tol = 0;
    memset(head,-1,sizeof(head));
}
void add(int u,int v,int w,int rw = 0){
    cw[tol].to = v;
    cw[tol].cap = w;
    cw[tol].nex = head[u];
    cw[tol].flow = 0;
    head[u] = tol++;
    cw[tol].to = u;
    cw[tol].cap = rw;
    cw[tol].nex = head[v];
    cw[tol].flow = 0;
    head[v] = tol++;
}
int sap(int start,int end,int N){
    memset(gap,0,sizeof(gap));
    memset(dep,0,sizeof(dep));
    memcpy(cur,head,sizeof(head));
    int u = start;
    pre[u] = -1;
    gap[0] = N;
    int ans = 0;
    while(dep[start] < N){
        if(u == end){
            int Min = INF;
            for(int i = pre[u]; i != -1;i = pre[cw[i^1].to])
                if(Min > cw[i].cap - cw[i].flow)
                    Min = cw[i].cap - cw[i].flow;
            for(int i = pre[u];i != -1;i = pre[cw[i^1].to]){
                cw[i].flow += Min;
                cw[i^1].flow -= Min;
            }
            u = start;
            ans += Min;
            continue;
        }
        bool flag = false;
        int v;
        for(int i = cur[u];i != -1;i = cw[i].nex){
            v = cw[i].to;
            if(cw[i].cap - cw[i].flow && dep[v] + 1 == dep[u]){
                flag = true;
                cur[u] = pre[v] = i;
                break;
            }
        }
        if(flag){
            u = v;
            continue;
        }
        int Min = N;
        for(int i = head[u];i != -1;i = cw[i].nex)
            if(cw[i].cap - cw[i].flow && dep[cw[i].to] < Min){
                Min = dep[cw[i].to];
                cur[u] = i;
            }
        gap[dep[u]]--;
        if(!gap[dep[u]])return ans;
        dep[u] = Min+1;
        gap[dep[u]]++;
        if(u != start)u = cw[pre[u]^1].to;
    }
    return ans;
}
int build(int k){
    init();
    int vs=0,vt=m+1;
    for(int i=1;i<=n;++i){
        add(vs,i,ar[i]);
        for(int j=i+1;j<=n;++j){
            if(i>=n-k+1&&ar[i]<ar[j]){
                add(i,mp[i][j],1);
            }else{
                add(i,mp[i][j],1);
                add(j,mp[i][j],1);
            }
            add(mp[i][j],vt,1);
        }
    }
    return sap(vs,vt,vt+1);
}
void cut(char *s){
    int len = strlen(s);  
    int t = 0;
    for(int i = 0; i < len; i++){
        if(s[i] >= '0' && s[i] <= '9'){
            t = t * 10 + s[i] - '0';
            if(i == len - 1 || s[i + 1] == ' '){
                ar[++n] = t;  
                t = 0;  
            }  
        }  
    }  
}  
int main(){
    int T;scanf("%d",&T);
    getchar();
    while(T--){n=0;
        memset(tools,0,sizeof(tools));
        gets(tools);
        cut(tools);
        m=n;
        for(int i=1;i<n;++i){
            for(int j=i+1;j<=n;++j){
                mp[i][j]=mp[j][i]=++m;
            }
        }
        for(int i=n;i>=1;--i){
            if(build(i)==n*(n-1)/2){
                printf("%d\n",i );
                break;
            }
        }
    }
    return 0;
}


题目描述:

Description

A tournament can be represented by a complete graph in which each vertex denotes a player and a directed edge is from vertex x to vertex y if player x beats player y. For a player x in a tournament T, the score of x is the number of players beaten by x. The score sequence of T, denoted by S(T) = (s1, s2, … , sn), is a non-decreasing list of the scores of all the players in T. It can be proved that S(T) = (s1, s2, … , sn) is a score sequence of T if and only if
for k = 1, 2, … , n and equality holds when k = n. A player x in a tournament is a strong king if and only if x beats all of the players whose scores are greater than the score of x. For a score sequence S, we say that a tournament T realizes S if S(T) = S. In particular, T is a heavy tournament realizing S if T has the maximum number of strong kings among all tournaments realizing S. For example, see T2 in Figure 1. Player a is a strong king since the score of player a is the largest score in the tournament. Player b is also a strong king since player b beats player a who is the only player having a score larger than player b. However, players c, d and e are not strong kings since they do not beat all of the players having larger scores.
The purpose of this problem is to find the maximum number of strong kings in a heavy tournament after a score sequence is given. For example,Figure 1 depicts two possible tournaments on five players with the same score sequence (1, 2, 2, 2, 3). We can see that there are at most two strong kings in any tournament with the score sequence (1, 2, 2, 2, 3) since the player with score 3 can be beaten by only one other player. We can also see that T2 contains two strong kings a and b. Thus, T2 is one of heavy tournaments. However, T1 is not a heavy tournament since there is only one strong king in T1. Therefore, the answer of this example is 2.

Input

The first line of the input file contains an integer m, m <= 10, which represents the number of test cases. The following m lines contain m score sequences in which each line contains a score sequence. Note that each score sequence contains at most ten scores.
Output

The maximum number of strong kings for each test case line by line.
Sample Input

5
1 2 2 2 3
1 1 3 4 4 4 4
3 3 4 4 4 4 5 6 6 6
0 3 4 4 4 5 5 5 6
0 3 3 3 3 3
Sample Output

2
4
5
3
5

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值