poj 2699 The Maximum Number of Strong Kings 【二分 + 竞赛图建模判断是否满流】

来源:互联网 发布:unity3d开发2d游戏 编辑:程序博客网 时间:2024/05/16 06:44
The Maximum Number of Strong Kings
Time Limit: 1000MS Memory Limit: 65536KTotal Submissions: 1839 Accepted: 860

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

51 2 2 2 31 1 3 4 4 4 43 3 4 4 4 4 5 6 6 60 3 4 4 4 5 5 5 60 3 3 3 3 3

Sample Output

2453

5

题意:有N个竞赛者,他们之间要进行N*(N-1)/2场比赛。初始分数都相等,对每一场比赛,胜者分数加一,败者分数不变。

要求某一个竞赛者是Strong King需要具备下面两个条件的任一个

1,分数最高;2,击败了所有比他分数高的竞赛者。

现在给出每个竞赛者在比赛中取胜的场次,问你最多可以同时存在多少个Strong King?

思路:二分后面连续的个数,建边后判断是否满流。 建图倒不是很难,主要证明下面。。。

证明 

对一个序列,如果有k个Strong Kings,那么必然存在一种情况(不是有且只有这一种情况),就是后k个人是Strong Kings。

借鉴大牛的证明思路

假设序列是1...i...j...k...n,其中i和k是strong kings,而j不是。

假设j输给了j+1至n区间中的x个人,那么显然i是赢了这x个人的,我们现在想把j变为strong kings。

那么就让把j输了的这些场全变成赢,此时分值改变了x,就将与i之前的人们的比赛多输x场,这样j的分数守恒了,但是j一赢之后,原本输给的x个人的分数少了,那就让他们都去赢i,这样他们的分数也就守恒了,此时发现i分数又不守恒了,少了x,恰好刚才j去输给i之前的人了x场,i正好去赢x场,这样大家的分数都守恒了,因此j也是Strong King。 得证。


建图:对当前查找的mid值(代表N-mid+1 到 N全是Strong King),设置超级源点S,超级汇点T

1,S到每一场比赛建边,容量为1,表示这场比赛的冠军只会有一个;

2,每个人向T建边,容量为他可以获胜的场次;

3,对于竞赛者i和j(j > i)以及他们的比赛编号num

若i >= N-mid+1 && score[i] < score[j],建边num -> i,容量为1,表示这场比赛竞赛者i必须要赢。

反之,建边num->i 和 num->j,容量为1,意味着两者谁赢都可以。

最后跑一次最大流,看在mid限制下,能够成功分配所有比赛。


AC代码:

#include <cstdio>#include <cstring>#include <cmath>#include <queue>#include <algorithm>#define MAXN 200#define MAXM 5000#define INF 0x3f3f3f3fusing namespace std;struct Edge{    int from, to, cap, flow, next;};Edge edge[MAXM];int head[MAXN], edgenum;int dist[MAXN], cur[MAXN];bool vis[MAXN];bool BFS(int s, int t){    queue<int> Q;    memset(dist, -1, sizeof(dist));    memset(vis, false, sizeof(vis));    dist[s] = 0;    vis[s] = true;    Q.push(s);    while(!Q.empty())    {        int u = Q.front();        Q.pop();        for(int i = head[u]; i != -1; i = edge[i].next)        {            Edge E = edge[i];            if(!vis[E.to] && E.cap > E.flow)            {                dist[E.to] = dist[u] + 1;                vis[E.to] = true;                if(E.to == t) return true;                Q.push(E.to);            }        }    }    return false;}int DFS(int x, int a, int t){    if(x == t || a == 0) return a;    int flow = 0, f;    for(int &i = cur[x]; i != -1; i = edge[i].next)    {        Edge &E = edge[i];        if(dist[E.to] == dist[x] + 1 && (f = DFS(E.to, min(a, E.cap-E.flow), t)) > 0)        {            edge[i].flow += f;            edge[i^1].flow -= f;            flow += f;            a -= f;            if(a == 0) break;        }    }    return flow;}int Maxflow(int s, int t){    int flow = 0;    while(BFS(s, t))    {        memcpy(cur, head, sizeof(head));        flow += DFS(s, INF, t);    }    return flow;}int score[MAXN];//每个人的分值int N;int S, T;//源点 汇点bool judge(char op){    return op >= '0' && op <= '9';}void input(){    char str[1010];    N = 0;    gets(str);    int len = strlen(str);    for(int i = 0; i < len; i++)    {        if(judge(str[i]))        {            int sum = 0;            while(judge(str[i]) && i < len)            {                sum = sum * 10 + str[i] - '0';                i++;            }            score[++N] = sum;        }    }}void init(){    edgenum = 0;    memset(head, -1, sizeof(head));}void addEdge(int u, int v, int w){    Edge E1 = {u, v, w, 0, head[u]};    edge[edgenum] = E1;    head[u] = edgenum++;    Edge E2 = {v, u, 0, 0, head[v]};    edge[edgenum] = E2;    head[v] = edgenum++;}void getMap(int mid)//后mid个 人为胜者{    init();    int num = 0;//比赛场次    for(int i = 1; i <= N; i++)    {        addEdge(i, T, score[i]);//每个人向汇点建边 容量为分值        for(int j = i+1; j <= N; j++)        {            num++, addEdge(S, num+N, 1);//源点向每场比赛建边容量为1            if(i >= N-mid+1 && score[i] < score[j])                addEdge(num+N, i, 1);            else                addEdge(num+N, i, 1), addEdge(num+N, j, 1);        }    }}void solve(){    int sum = N * (N - 1) / 2;    S = 0, T = sum + N + 1;    int left = 0, right = N, mid;    int ans = 0;    while(right >= left)    {        int mid = (right + left) >> 1;        getMap(mid);        if(Maxflow(S, T) == sum)//满流  符合            left = mid + 1, ans = mid;        else            right = mid - 1;    }    printf("%d\n", ans);}int main(){    int t;    scanf("%d", &t);    getchar();    while(t--)    {        input();        solve();    }    return 0;}



0 0