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;
}
为了更好的明天