POJ - 2699 The Maximum Number of Strong Kings (最大流+枚举)

题意:有n(n<=10)个选手,两两之间打比赛,共有n*(n-1)/2场比赛,赢一场得1分。给出每个人最后的得分。求有多少个定义如下的strong king:赢了所有得分比自己高的人或本身就是分数最高的人。

更详细的说明:https://blog.csdn.net/sdj222555/article/details/7797257

分析:因为n很小,枚举人数是一种可行的做法,网络流求解。具体的建图方法是:
1.从源点向每个选手i建一条容量为val[i]的弧;
2.将每场比赛视作点,由每场比赛向汇点建一条容量为1的弧;
3.一对选手i和j之间,若val[i]<val[j]且i是 strong king,那么i向该场比赛的编号建一条容量为1的弧,表示i赢下了该场比赛。
跑出最大流f,若f等于比赛数,说明该情况下能得到正确比赛结果。
最暴力的方法是二进制枚举可能的strong king情况,复杂度能够接受。而链接博客中给出的做法却是十分精妙的枚举。

#include<iostream>
#include<stdio.h>
#include<cstring>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<cmath>
#include<algorithm>
using namespace std;
const int INF = 0x3f3f3f3f;
const int MAXN=1010;//点数的最大值
const int MAXM=400010;//边数的最大值
#define captype int

struct SAP_MaxFlow{
    struct EDGE{
        int to,next;
        captype cap;
    }edg[MAXM];
    int eid,head[MAXN];
    int gap[MAXN];
    int dis[MAXN];
    int cur[MAXN];
    int pre[MAXN];

    void init(){
        eid=0;
        memset(head,-1,sizeof(head));
    }
    void AddEdge(int u,int v,captype c,captype rc=0){
        edg[eid].to=v; edg[eid].next=head[u];
        edg[eid].cap=c;  head[u]=eid++;
        edg[eid].to=u; edg[eid].next=head[v];
        edg[eid].cap=rc; head[v]=eid++;
    }
    captype maxFlow_sap(int sNode,int eNode, int n){//n是包括源点和汇点的总点个数,这个一定要注意
        memset(gap,0,sizeof(gap));
        memset(dis,0,sizeof(dis));
        memcpy(cur,head,sizeof(head));
        pre[sNode] = -1;
        gap[0]=n;
        captype ans=0;
        int u=sNode;
        while(dis[sNode]<n){
            if(u==eNode){
                captype Min=INF ;
                int inser;
                for(int i=pre[u]; i!=-1; i=pre[edg[i^1].to])
                if(Min>edg[i].cap){
                    Min=edg[i].cap;
                    inser=i;
                }
                for(int i=pre[u]; i!=-1; i=pre[edg[i^1].to]){
                    edg[i].cap-=Min;
                    edg[i^1].cap+=Min;
                }
                ans+=Min;
                u=edg[inser^1].to;
                continue;
            }
            bool flag = false;
            int v;
            for(int i=cur[u]; i!=-1; i=edg[i].next){
                v=edg[i].to;
                if(edg[i].cap>0 && dis[u]==dis[v]+1){
                    flag=true;
                    cur[u]=pre[v]=i;
                    break;
                }
            }
            if(flag){
                u=v;
                continue;
            }
            int Mind= n;
            for(int i=head[u]; i!=-1; i=edg[i].next)
            if(edg[i].cap>0 && Mind>dis[edg[i].to]){
                Mind=dis[edg[i].to];
                cur[u]=i;
            }
            gap[dis[u]]--;
            if(gap[dis[u]]==0) return ans;
            dis[u]=Mind+1;
            gap[dis[u]]++;
            if(u!=sNode) u=edg[pre[u]^1].to;  //退一条边
        }
        return ans;
    }
}F;

char str[1000];
int val[20];
int id[12][12];
int n,m,s,t;
bool vis[12][12];

void input()
{
    n = 0;
    int len = strlen(str);
    int w=0;
    for(int i=0;i<len;++i){
        if(str[i]>='0' && str[i]<='9'){
            w = w*10 + str[i]-'0';
            if(i==len-1 || str[i+1]==' '){
                val[++n] = w;
                w = 0;
            }
        }
    }
}

void build(int k)
{
    F.init();
    for(int i = 1; i <= n; i++) F.AddEdge(s, i, val[i]);
    for(int i = n + 1; i <= m; i++) F.AddEdge(i, t, 1);
    memset(vis, 0, sizeof(vis));
    for(int i = n - k + 1; i <= n; i++)
        for(int j = i + 1; j <= n; j++)
            if(val[i] < val[j])
                F.AddEdge(i, id[i][j], 1), vis[i][j] = 1;
    for(int i = 1; i <= n; i++){
        for(int j = i + 1; j <= n; j++){
            if(!vis[i][j]){
                F.AddEdge(i, id[i][j], 1);
                F.AddEdge(j, id[i][j], 1);
            }
        }
    }
}

int main()
{
	#ifndef ONLINE_JUDGE
        freopen("in.txt","r",stdin);
        freopen("out.txt","w",stdout);
    #endif
    int T; scanf("%d",&T);
    getchar();
    while(T--){
        gets(str);
        input();
        m = n;
        for(int i=1;i<=n;++i){
            for(int j=i+1;j<=n;++j){
                id[i][j] = id[j][i] = ++m;
            }
        }
        int ans = 0;
        s =0 ,t = m+1;
        for(int i=n;i>=1;--i){
            build(i);
            if(F.maxFlow_sap(s,t,t+1)==n*(n-1)/2){
                ans = i;
                break;
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}
posted @ 2018-09-19 19:17  xiuwenL  阅读(117)  评论(0编辑  收藏  举报