poj2699 竞赛图+网络流

这道题是个不错的题

【题意】

n个人比赛, 两两比,共n*(n-1), 赢得1分, n<=10(这给了我们枚举的暗示)

如果一个人打败了所有比自己分数高的人, 或者他本身就是分数最高的, 那么他就是

StrongKing

可能有多个Strong King, 现在按非降的顺序给你每个人的得分(不难道想到容量把), 问

Strong King最多能有几个

【解答】

一般遇到竞赛图,网络流的可能性较大,因为竞赛图中的条件都与点的度数有关。

建图:二分图,左边是人,右边是比赛,源点到人连容量为score[i]的边,汇点到比赛连

量为1的边。然后枚举答案ans,由于分数越高的人成为

strongking的可能性较大(我一开始没有意识到这点,还想用2^10的枚举),于是让后

ans人成为strongking,然后对这ans个人中的i,j,如果score[i]<score[j]则i像match[i]

[j]连容量为一的边。然后对剩余的比赛match[i][j],让i,j向点match[i][j]连容量为1的边。

当maxflow==n*(n-1)/2时,则ans为解

#include <iostream>
#include <cstring>
#include <string>
#include <sstream>
using namespace std;

const int oo=200000;
struct edge
{
       int x,y,f,next,op;
}e[2000];
int g[20],m[20][20],h[100],d[100],p[100],now[100],num[100],f[100];
int n,s,t,tot,tt;
void ins(int x,int y,int f)
{
     e[++tot].x=x;e[tot].y=y;
     e[tot].next=h[x];e[tot].f=f;
     h[x]=tot;
     e[++tot].x=y;e[tot].y=x;
     e[tot].next=h[y];e[tot].f=0;
     h[y]=tot;
     e[tot].op=tot-1;e[tot-1].op=tot;
}

void build(int num)
{
     tot=0;
     int i,j;
     memset(f,0,sizeof(f));
     memset(h,0,sizeof(h));
     for (i=1;i<=n;i++)
         ins(s,i,g[i]);
     for (i=1;i<=tt;i++)
         ins(i+n,t,1);
     for (i=n-num+1;i<=n;i++)
         for (j=i+1;j<=n;j++)
         if (g[j]>g[i])
         {
             f[m[i][j]]=1;
             ins(i,m[i][j]+n,1);
         }
     for (i=1;i<=n;i++)
         for (j=i+1;j<=n;j++)
         if (!f[m[i][j]])
         {
             ins(i,m[i][j]+n,1);
             ins(j,m[i][j]+n,1);
         }
}

int isap()
{
    int flow=0,aug=oo,u,v,tmp,i,j,ff;
    for (i=0;i<=t;i++)
    {
        d[i]=0;p[i]=-1;
        num[i]=0;now[i]=h[i];
    }
    num[0]=t+1;u=s;
    while (d[s]<t+1)
    {
          for (ff=0,i=now[u];i;i=e[i].next)
          {
              v=e[i].y;
              if (e[i].f && d[u]==d[v]+1)
              {
                 ff=1;
                 if (e[i].f<aug) aug=e[i].f;
                 p[v]=i;now[u]=i;
                 u=v;
                 if (u==t)
                 {
                    flow+=aug;
                    while (u!=s)
                    {
                          j=p[u];
                          e[j].f-=aug;
                          e[e[j].op].f+=aug;
                          u=e[j].x;
                    }
                    aug=oo;
                 }
                 break;
              }
          }
          if (ff) continue;
          num[d[u]]--;
          if (!num[d[u]]) return flow;
          tmp=t+1;
          for (i=h[u];i;i=e[i].next)
          {
              v=e[i].y;
              if (e[i].f && d[v]<tmp) 
              {
                 tmp=d[v];now[u]=i;
              }
          }
          d[u]=tmp+1;
          num[d[u]]++;
          if (u!=s) u=e[p[u]].x;
    }
    return flow;
}

int main()
{
    freopen("pin.txt","r",stdin);
    freopen("pou.txt","w",stdout);
    char str[40];
    int i,j,cc;
    cin >> cc;
    getchar();
    while (cc--)
    {
          gets(str);
          stringstream ss(str);
          n=0;
          while (ss >> j)
                g[++n]=j;
          tt=0;
          for (i=1;i<=n;i++)
              for (j=i+1;j<=n;j++)
                  m[i][j]=++tt;
          s=0;t=tt+n+1;
          for (i=n;i>1;i--)
          {
              build(i);
              if (isap()==(n*(n-1))/2) break;
          }
          cout << i << endl;
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值