题意:
有n个队伍,两两都有比赛
知道最后每支队伍获胜的场数
求最多有多少队伍,他们战胜了所有获胜场数比自己多的队伍,这些队伍被称为SK
N<=50
思路:把每个队伍和它们两两之间的比赛都当做点,判断最大流是否满流即可
S——>队伍 a[i]
队伍 ——>比赛 1
比赛——>T 1
i号队伍是SK:如果j为SK且a[i]>a[j]则j必胜,如果a[i]<a[j]则i必胜 只要必胜者向他们之间的比赛连1条边即可
如果j不为SK,胜负未知,两个点都向他们之间的比赛连1条边
i号队伍不是SK:对于所有的队伍都胜负未知,同上处理
最暴力的思想就是枚举每个队伍作为SK的可能性再根据得分情况连边,其实也能过
不过可以证明一定存在一种方案,使得SK是排序后得分最多的那些队伍
二分或枚举答案即可
证明见http://blog.csdn.net/sdj222555/article/details/7797257
var head,a:array[..]of longint;
fan:array[..]of longint;
vet,next,len,dis,gap,flag:array[..]of longint;
num:array[..,..]of longint;
n,i,j,tot,l,r,mid,last,s,source,src,cas,v,k:longint;
ch:ansistring; function min(x,y:longint):longint;
begin
if x<y then exit(x);
exit(y);
end; procedure add(a,b,c:longint);
begin inc(tot);
next[tot]:=head[a];
vet[tot]:=b;
len[tot]:=c;
head[a]:=tot; inc(tot);
next[tot]:=head[b];
vet[tot]:=a;
len[tot]:=;
head[b]:=tot; end; procedure swap(var x,y:longint);
var t:longint;
begin
t:=x; x:=y; y:=t;
end; procedure qsort(l,r:longint);
var i,j,mid:longint;
begin
i:=l; j:=r; mid:=a[(l+r)>>];
repeat
while mid<a[i] do inc(i);
while mid>a[j] do dec(j);
if i<=j then
begin
swap(a[i],a[j]);
inc(i); dec(j);
end;
until i>j;
if l<j then qsort(l,j);
if i<r then qsort(i,r);
end; function dfs(u,aug:longint):longint;
var e,v,t,val,flow:longint;
begin
if u=src then exit(aug);
e:=head[u]; val:=s-; flow:=;
while e<> do
begin
v:=vet[e];
if len[e]> then
begin
if dis[u]=dis[v]+ then
begin
t:=dfs(v,min(len[e],aug-flow));
len[e]:=len[e]-t;
len[fan[e]]:=len[fan[e]]+t;
flow:=flow+t;
if dis[source]>=s then exit(flow);
if aug=flow then break;
end;
val:=min(val,dis[v]);
end;
e:=next[e];
end;
if flow= then
begin
dec(gap[dis[u]]);
if gap[dis[u]]= then dis[source]:=s;
dis[u]:=val+;
inc(gap[dis[u]]);
end;
exit(flow);
end; function maxflow:longint;
var ans:longint;
begin
fillchar(gap,sizeof(gap),);
fillchar(dis,sizeof(dis),);
gap[]:=s; ans:=;
while dis[source]<s do ans:=ans+dfs(source,maxlongint);
exit(ans);
end; procedure build(k:longint);
var i,j:longint;
begin
fillchar(flag,sizeof(flag),);
fillchar(head,sizeof(head),); tot:=; for i:= to k do
begin
for j:= to i- do
begin
flag[num[i,j]]:=;
add(i,num[i,j],);
end;
for j:=i+ to n do
if (a[j]<a[i])and(j<=k)and(flag[num[i,j]]=) then
begin
flag[num[i,j]]:=;
add(j,num[i,j],);
end
else if flag[num[i,j]]= then
begin
flag[num[i,j]]:=;
add(i,num[i,j],);
add(j,num[i,j],);
end;
end;
for i:=k+ to n do
for j:= to n do
if (i<>j)and(flag[num[i,j]]=) then
begin
add(i,num[i,j],);
add(j,num[i,j],);
flag[num[i,j]]:=;
end;
for i:= to n do add(source,i,a[i]);
for i:= to n do
for j:= to n do
if i<j then add(num[i,j],src,);
end; function isok(k:longint):boolean;
begin
if maxflow=n*(n-) div then exit(true);
exit(false);
end; begin
assign(input,'poj2699.in'); reset(input);
assign(output,'poj2699.out'); rewrite(output);
for i:= to do
if i mod = then fan[i]:=i+
else fan[i]:=i-;
readln(cas);
for v:= to cas do
begin
fillchar(num,sizeof(num),);
readln(ch); k:=length(ch);
fillchar(a,sizeof(a),); n:=;
i:=;
while i<k do
begin
inc(i);
while (i<k)and(ch[i]=' ') do inc(i);
inc(n);
while (i<=k)and(ch[i]<>' ') do
begin
a[n]:=a[n]*+ord(ch[i])-ord('');
inc(i);
end;
end; qsort(,n); s:=n;
for i:= to n do
for j:= to n do
if i<>j then
begin
if num[j,i]= then
begin
inc(s); num[i,j]:=s;
end
else num[i,j]:=num[j,i];
end;
inc(s); source:=s; inc(s); src:=s; l:=; r:=n; last:=;
while l<=r do
begin
mid:=(l+r)>>;
build(mid);
if isok(mid) then begin last:=mid; l:=mid+; end
else r:=mid-;
end;
writeln(last);
end;
close(input);
close(output);
end.