poj2699 暴力+dinic

The Maximum Number of Strong Kings
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 1689 Accepted: 789

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

这题建模有点难,想不到!

这里有份题解,很详细! 传送门:题解

首先要想到暴力,并且越靠后越可能成为Strong King,上面的题解有证明过程:

假设序列是这个模样,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去赢 j+1至n区间中的x个人,那么分数高了x分,必须多输给区间[1...j-1]之间x场,这说明原先j至少赢区间[1...j-1]之间x场,否则无法多输x场。

所以解释一下为什么j一定会赢区间[1...j-1]之间x场,我们看证明中的i比j在区间[j+1,n]多赢了x场,而j的编号大于i,因为分数序列非降,所以j的分数要大于等于i的分数,那么只有一种可能,j必须比i在区间[1,j-1]多赢至少x场,这样就算i在区间[1,j-1]赢0场,就也能赢至少x场,这样证明就非常完善了!

注意:对于一个序列,如果有k个strong kings,那么必然存在一种情况,就是后k个人是strong kings。注意,是‘存在’,而不是‘必然是‘。 

代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#define Maxn 100
using namespace std;

char s[Maxn];
int seq[Maxn];
const int inf=0x3f3f3f3f;
struct line{
    int to,next,cap;
}p[Maxn*Maxn];
int head[Maxn];
int q[Maxn];
int d[Maxn];
int tot;
int src,t;
int n,m;
void addedge(int a,int b,int c){
    p[tot].to=b;
    p[tot].next=head[a];
    p[tot].cap=c;
    head[a]=tot++;
}
void insert(int a,int b,int c){
    addedge(a,b,c);
    addedge(b,a,0);
}
bool bfs(){
    memset(d,-1,sizeof d);
    int s=0,e=-1;
    q[++e]=src;
    d[src]=0;
    while(s<=e){
        int u=q[s++];
        for(int i=head[u];i!=-1;i=p[i].next){
            int v=p[i].to;
            if(d[v]==-1&&p[i].cap){
                d[v]=d[u]+1;
                q[++e]=v;
            }
        }
    }
    return d[t]!=-1;
}
int dfs(int u,int alpha){
    if(u==t) return alpha;
    int w,used=0;
    for(int i=head[u];i!=-1&&used<alpha;i=p[i].next){
        int v=p[i].to;
        if(p[i].cap&&d[v]==d[u]+1){
            w=dfs(v,min(alpha-used,p[i].cap));
            used+=w;
            p[i].cap-=w;
            p[i^1].cap+=w;
        }
    }
    if(!used) d[u]=-1;
    return used;
}
int dinic(){
    int ans=0;
    src=0;
    while(bfs())
        ans+=dfs(src,inf);
    return ans;
}
void add(int k){
    memset(head,-1,sizeof head);
    tot=0;
    for(int i=1;i<=n;i++)
        insert(0,i,seq[i]);
    t=n+1;
    for(int i=1;i<n;i++)
        for(int j=i+1;j<=n;j++){
            if(i+k>=n+1&&seq[i]<seq[j]) insert(i,t,1); //i是Strong King
            else{
                insert(i,t,1);
                insert(j,t,1);
            }
            t++;
        }
    for(int i=n+1;i<t;i++) insert(i,t,1); //连向汇点
}
int main()
{
    int cas;
    cin>>cas;
    gets(s);
    while(cas--){
        n=0;
        int res=0,x=0;
        gets(s);
        bool flag=false;
        for(int i=0;s[i];i++){
            if(s[i]==' '){
                if(flag) {seq[++n]=x;res+=x;}
                flag=false;
                x=0;
            }
            else{
                flag=true;
                x=x*10+s[i]-'0';
            }
        }
        if(flag) {seq[++n]=x;res+=x;}
        for(int i=n;i>=0;i--){ //枚举
            add(i);
            if(dinic()==res){
                res=i;
                break;
            }
        }
        printf("%d\n",res);
    }
	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值