您的位置:首页 > 其它

[省选前题目整理][POJ 2699]The Maximum Number of Strong Kings(暴力枚举+最大流)

2015-03-29 18:47 519 查看

题目链接

http://poj.org/problem?id=2699

题目大意

n个人比赛, 两两比,共n(n-1)场比赛, 赢的人得1分, n<=10。如果一个人打败了所有比自己分数高的人, 或者他本身就是分数最高的, 那么他就是StrongKing。可能有多个Strong King, 现在按非降的顺序给你每个人的得分(不难道想到容量把), 问Strong King最多能有几个。

思路

显然n个人之间的比赛关系可以构成一个竞赛图。竞赛图问题往往可以用网络流解决,此题也是如此。鉴于某个答案的猜测值的可行性随着答案大小单调改变,很自然地想到用二分来解决此题。那么我们就要二分Strong King的个数ans。下面的问题变成了,已知Strong King的个数ans,求这个答案是否大于实际答案(不成立)。

不妨把每个人看成一个个点(如下图的蓝色点),每个比赛也看成一个个点(如下图的绿色点)。每个比赛向T连容量为1的边(表示赢得一场比赛能得到1分),S向每个人连容量为该人获得分数的边(表示这个人最多只能赢这么多分)。

然后对于后ans个人来说,由于输入的分数是升序的,因此它们是我们假定的Strong Kings。在这些人中,如果人i的分比人j低,那么就从人i向这两个人的比赛对应的点连容量为1的边(显然i和j的胜负已定,根据规则,i比j的分低,而i也是Strong King,那么一定是i赢了这场比赛)。对于所有人来说,任意两个人a、b,分别向他们之间的比赛对应的点连容量为1的边(表明对于其他人来说,他们既可以赢,也可以输)。

最终这个图的最大流就是在Strong Kings个数为ans的情况下能够进行的比赛场数(所有人的分数之和),显然比赛场数是n*(n-1)场,若最大流不等于n*(n-1),那么就表明Strong Kings个数为ans的情况是不合法的。

代码

#include <sstream>
#include <string>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>

#define MAXV 1000
#define MAXE 3000
#define MAXN 1000
#define INF 0x3f3f3f3f

using namespace std;

int S,T;

struct edge
{
int u,v,cap,next;
}edges[MAXE];

int head[MAXV],nCount=1;

void AddEdge(int U,int V,int C)
{
edges[++nCount].u=U;
edges[nCount].v=V;
edges[nCount].cap=C;
edges[nCount].next=head[U];
head[U]=nCount;
}

void add(int U,int V,int C)
{
AddEdge(U,V,C);
AddEdge(V,U,0);
}

int layer[MAXV],q[MAXE*2];

bool CountLayer()
{
memset(layer,-1,sizeof(layer));
int h=0,t=1;
q[h]=S;
layer[S]=1;
while(h<t)
{
int u=q[h++];
for(int p=head[u];p!=-1;p=edges[p].next)
{
int v=edges[p].v;
if(layer[v]==-1&&edges[p].cap)
{
layer[v]=layer[u]+1;
q[t++]=v;
}
}
}
return layer[T]!=-1;
}

int DFS(int u,int flow)
{
if(u==T) return flow;
int used=0;
for(int p=head[u];p!=-1;p=edges[p].next)
{
int v=edges[p].v;
if(layer[v]==layer[u]+1&&edges[p].cap)
{
int tmp=DFS(v,min(flow-used,edges[p].cap));
used+=tmp;
edges[p].cap-=tmp;
edges[p^1].cap+=tmp;
if(used==flow) return used;
}
}
if(!used) layer[u]=-1;
return used;
}

int Dinic()
{
int maxflow=0;
while(CountLayer())
maxflow+=DFS(S,INF);
return maxflow;
}

int n=0,tot=0;
int match[MAXN][MAXN],score[MAXN];
bool matched[MAXN*MAXN];
char s[MAXN];

bool check(int x) //已知有x个Strong Kings
{
S=MAXV-2,T=MAXV-1;
nCount=1;
memset(head,-1,sizeof(head));
memset(matched,false,sizeof(matched));
for(int i=1;i<=n;i++)
add(S,i,score[i]);
for(int i=1;i<=tot;i++)
add(i+n,T,1);
for(int i=n-x+1;i<=n;i++)
for(int j=i+1;j<=n;j++)
if(score[j]>score[i])
{
matched[match[i][j]]=true;
add(i,match[i][j]+n,1);
}
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++)
if(!matched[match[i][j]])
{
add(i,match[i][j]+n,1);
add(j,match[i][j]+n,1);
}
return Dinic()==(n*(n-1)/2);
}

int main()
{
int TestCase;
scanf("%d",&TestCase);
getchar(); //!!!!
while(TestCase--)
{
memset(head,-1,sizeof(head));
nCount=1;
n=0,tot=0;
int tmp;
gets(s);
stringstream str(s);
while(str>>tmp) score[++n]=tmp;
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++)
match[i][j]=++tot;
int ans;
for(int i=n;i>=1;i--)
if(check(i))
{
ans=i;
break;
}
printf("%d\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: