zoukankan      html  css  js  c++  java
  • POJ

    题意:有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
    ",ans);
        }
        return 0;
    }
    
    为了更好的明天
  • 相关阅读:
    单元測试和白盒測试相关总结
    数据结构:图的实现--邻接矩阵
    Android提示版本号更新操作流程
    《集体智慧编程》代码勘误:第六章
    LINUX设备驱动程序笔记(三)字符设备驱动程序
    数学定理证明机械化的中国学派(II)
    《Java并发编程实战》第三章 对象的共享 读书笔记
    Linux系列-安装经常使用软件
    Kubuntu 初始配置
    虚拟互换(virtual swap)
  • 原文地址:https://www.cnblogs.com/xiuwenli/p/9676482.html
Copyright © 2011-2022 走看看