POJ 2699 最大流 竞赛图
2015-10-22 00:06
561 查看
The Maximum Number of Strong Kings
Description
A tournament can be represented by a complete graph in which each vertex denotes a player and a directed edge is from vertex x to vertex y if player x beats player y. For a player x in a tournament T, the score of x is the number of players beaten by x. The
score sequence of T, denoted by S(T) = (s1, s2, . . . , sn), is a non-decreasing list of the scores of all the players in T. It can be proved that S(T) = (s1, s2, . . . , sn) is a score sequence of T if and only if
![](http://poj.org/images/2699_1.jpg)
for k = 1, 2, . . . , n and equality holds when k = n. A player x in a tournament is a strong king if and only if x beats all of the players whose scores are greater than the score of x. For a score sequence S, we say that a tournament T realizes S if S(T)
= S. In particular, T is a heavy tournament realizing S if T has the maximum number of strong kings among all tournaments realizing S. For example, see T2 in Figure 1. Player a is a strong king since the score of player a is the largest score in the tournament.
Player b is also a strong king since player b beats player a who is the only player having a score larger than player b. However, players c, d and e are not strong kings since they do not beat all of the players having larger scores.
The purpose of this problem is to find the maximum number of strong kings in a heavy tournament after a score sequence is given. For example,Figure 1 depicts two possible tournaments on five players with the same score sequence (1, 2, 2, 2, 3). We can see that
there are at most two strong kings in any tournament with the score sequence (1, 2, 2, 2, 3) since the player with score 3 can be beaten by only one other player. We can also see that T2 contains two strong kings a and b. Thus, T2 is one of heavy tournaments.
However, T1 is not a heavy tournament since there is only one strong king in T1. Therefore, the answer of this example is 2.
![](http://poj.org/images/2699_2.jpg)
Input
The first line of the input file contains an integer m, m <= 10, which represents the number of test cases. The following m lines contain m score sequences in which each line contains a score sequence. Note that each score sequence contains at most ten scores.
Output
The maximum number of strong kings for each test case line by line.
Sample Input
Sample Output
题意是给你他们每个人的胜场数,问有多少最强竞赛者(指的如果胜场是最多的。或者赢了所有胜利数比他多的)
本来想二分胜利场数,后来想想不对。需要二分胜利人数
然后是建图:
超级源点连向人的流量是人的胜利场数
比赛连向超级汇点的流量是1
人连向比赛的流量是1 这里需要考虑如果这个人比另外一个人比赛场数低,且也在最强者里面,那么这把比赛他必须赢,所以只能连这个人到比赛的连线,其他的话从这两个人,各连一条到比赛,代表他们都能够去赢这场比赛。
因为数据比较小,我直接暴力枚举了。。并没有用二分。。。
#include <iostream>
#include <cstdio>
#include <climits>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <queue>
#include <algorithm>
#define esp 1e-6
#define inf 0x0f0f0f0f
#define LL long long
using namespace std;
const int MAXN = 100010 ; //点数最大值
const int MAXM = 400010 ; //边数最大值
const int INF = 0x3f3f3f3f;
int M,TOL,S,V;
struct Edge{
int to,next,cap,flow;
}edge[MAXM];//注意是MAXM
int tol;
int head[MAXN];
int gap[MAXN],dep[MAXN],pre[MAXN],cur[MAXN];
//int imap[333][333];
int b[13],co[13][13];
int cmp(int a,int b){
return a>b;
}
void init(){
tol = 0;
memset(head,-1,sizeof(head));
}
void addedge(int u,int v,int w,int rw=0){
edge[tol].to = v;
edge[tol].cap = w;
edge[tol].next = head[u];
edge[tol].flow = 0;
head[u] = tol++;
edge[tol].to = u;
edge[tol].cap = rw;
edge[tol].next = head[v];
edge[tol].flow = 0;
head[v] = tol++;
}
//最大流开始
int sap(int start,int end,int N){
memset(gap,0,sizeof(gap));
memset(dep,0,sizeof(dep));
memcpy(cur,head,sizeof(head));
int u = start;
pre[u] = -1;
gap[0] = N;
int ans = 0;
while(dep[start] < N){
if(u==end){
int Min = INF;
for(int i=pre[u];i!= -1; i=pre[edge[i^1].to])
if(Min > edge[i].cap - edge[i].flow)
Min = edge[i].cap - edge[i].flow;
for(int i=pre[u];i!=-1;i=pre[edge[i^1].to]){
edge[i].flow += Min;
edge[i^1].flow -=Min;
}
u=start;
ans +=Min;
continue;
}
bool flag = false;
int v;
for(int i= cur[u];i!=-1;i=edge[i].next){
v=edge[i].to;
if(edge[i].cap-edge[i].flow&&dep[v]+1==dep[u]){
flag=true;
cur[u]=pre[v]=i;
break;
}
}
if(flag){
u=v;
continue;
}
int Min = N;
for(int i=head[u];i!= -1;i=edge[i].next)
if(edge[i].cap-edge[i].flow&&dep[edge[i].to]<Min){
Min=dep[edge[i].to];
cur[u] = i;
}
gap[dep[u]]--;
if(!gap[dep[u]]) return ans;
dep[u] = Min +1;
gap[dep[u]]++;
if(u!=start) u = edge[pre[u]^1].to;
}
return ans;
}
//最大流结束
//构图
void build(int mid){
int i,j;
S=TOL+1;
V=TOL+2;
//超级源点 到每个人
for(i=0;i<M;i++){
addedge(S,i,b[i]);
}
//每场比赛到超级汇点
for(i=0;i<M;i++){
for(j=i+1;j<M;j++){
addedge(co[i][j],V,1);
}
}
//人到比赛
for(i=0;i<M;i++){
for(j=i+1;j<M;j++){
if(i<mid&&j<mid){
if(b[i]>b[j]){
addedge(j,co[i][j],1);
}
else if(b[i]<b[j]){
addedge(i,co[i][j],1);
}
else{
addedge(j,co[i][j],1);
addedge(i,co[i][j],1);
}
}
else{
addedge(j,co[i][j],1);
addedge(i,co[i][j],1);
}
}
}
}
//二分枚举解题
bool solve(int mid){
init();
build(mid);
int k=sap(S,V,V+1);
// printf("k=%d\n",k);
return k==TOL-M+1;
}
int main(){
int i,j,k,l,m,n;
int T;
scanf("%d\n",&T);
char a;
while(T--){
i=0;
while(1){
scanf("%c",&a);
if(a=='\n'||a=='\0'){
break;
}
else{
if(a!=' '){
b[i++]=a-'0';
}
}
}
//printf("%d\n",b[0]);
M=i;
sort(b,b+M,cmp);
int num=M;
// printf("M= %d\n",M);
for(i=0;i<M;i++){
for(j=i+1;j<M;j++){
co[i][j]=num++;
}
}
TOL=num-1;
// printf("TOL= %d\n",TOL);
// for(int aa=0;aa<M;aa++) printf("%d ",b[aa]);
int l=0,orz;
for(i=1;i<=M;i++){
if(solve(i)){
orz=i;
}
else break;
}
printf("%d\n",orz);
}
}
Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 1842 | Accepted: 862 |
A tournament can be represented by a complete graph in which each vertex denotes a player and a directed edge is from vertex x to vertex y if player x beats player y. For a player x in a tournament T, the score of x is the number of players beaten by x. The
score sequence of T, denoted by S(T) = (s1, s2, . . . , sn), is a non-decreasing list of the scores of all the players in T. It can be proved that S(T) = (s1, s2, . . . , sn) is a score sequence of T if and only if
![](http://poj.org/images/2699_1.jpg)
for k = 1, 2, . . . , n and equality holds when k = n. A player x in a tournament is a strong king if and only if x beats all of the players whose scores are greater than the score of x. For a score sequence S, we say that a tournament T realizes S if S(T)
= S. In particular, T is a heavy tournament realizing S if T has the maximum number of strong kings among all tournaments realizing S. For example, see T2 in Figure 1. Player a is a strong king since the score of player a is the largest score in the tournament.
Player b is also a strong king since player b beats player a who is the only player having a score larger than player b. However, players c, d and e are not strong kings since they do not beat all of the players having larger scores.
The purpose of this problem is to find the maximum number of strong kings in a heavy tournament after a score sequence is given. For example,Figure 1 depicts two possible tournaments on five players with the same score sequence (1, 2, 2, 2, 3). We can see that
there are at most two strong kings in any tournament with the score sequence (1, 2, 2, 2, 3) since the player with score 3 can be beaten by only one other player. We can also see that T2 contains two strong kings a and b. Thus, T2 is one of heavy tournaments.
However, T1 is not a heavy tournament since there is only one strong king in T1. Therefore, the answer of this example is 2.
![](http://poj.org/images/2699_2.jpg)
Input
The first line of the input file contains an integer m, m <= 10, which represents the number of test cases. The following m lines contain m score sequences in which each line contains a score sequence. Note that each score sequence contains at most ten scores.
Output
The maximum number of strong kings for each test case line by line.
Sample Input
5 1 2 2 2 3 1 1 3 4 4 4 4 3 3 4 4 4 4 5 6 6 6 0 3 4 4 4 5 5 5 6 0 3 3 3 3 3
Sample Output
2 4 5 3 5
题意是给你他们每个人的胜场数,问有多少最强竞赛者(指的如果胜场是最多的。或者赢了所有胜利数比他多的)
本来想二分胜利场数,后来想想不对。需要二分胜利人数
然后是建图:
超级源点连向人的流量是人的胜利场数
比赛连向超级汇点的流量是1
人连向比赛的流量是1 这里需要考虑如果这个人比另外一个人比赛场数低,且也在最强者里面,那么这把比赛他必须赢,所以只能连这个人到比赛的连线,其他的话从这两个人,各连一条到比赛,代表他们都能够去赢这场比赛。
因为数据比较小,我直接暴力枚举了。。并没有用二分。。。
#include <iostream>
#include <cstdio>
#include <climits>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <queue>
#include <algorithm>
#define esp 1e-6
#define inf 0x0f0f0f0f
#define LL long long
using namespace std;
const int MAXN = 100010 ; //点数最大值
const int MAXM = 400010 ; //边数最大值
const int INF = 0x3f3f3f3f;
int M,TOL,S,V;
struct Edge{
int to,next,cap,flow;
}edge[MAXM];//注意是MAXM
int tol;
int head[MAXN];
int gap[MAXN],dep[MAXN],pre[MAXN],cur[MAXN];
//int imap[333][333];
int b[13],co[13][13];
int cmp(int a,int b){
return a>b;
}
void init(){
tol = 0;
memset(head,-1,sizeof(head));
}
void addedge(int u,int v,int w,int rw=0){
edge[tol].to = v;
edge[tol].cap = w;
edge[tol].next = head[u];
edge[tol].flow = 0;
head[u] = tol++;
edge[tol].to = u;
edge[tol].cap = rw;
edge[tol].next = head[v];
edge[tol].flow = 0;
head[v] = tol++;
}
//最大流开始
int sap(int start,int end,int N){
memset(gap,0,sizeof(gap));
memset(dep,0,sizeof(dep));
memcpy(cur,head,sizeof(head));
int u = start;
pre[u] = -1;
gap[0] = N;
int ans = 0;
while(dep[start] < N){
if(u==end){
int Min = INF;
for(int i=pre[u];i!= -1; i=pre[edge[i^1].to])
if(Min > edge[i].cap - edge[i].flow)
Min = edge[i].cap - edge[i].flow;
for(int i=pre[u];i!=-1;i=pre[edge[i^1].to]){
edge[i].flow += Min;
edge[i^1].flow -=Min;
}
u=start;
ans +=Min;
continue;
}
bool flag = false;
int v;
for(int i= cur[u];i!=-1;i=edge[i].next){
v=edge[i].to;
if(edge[i].cap-edge[i].flow&&dep[v]+1==dep[u]){
flag=true;
cur[u]=pre[v]=i;
break;
}
}
if(flag){
u=v;
continue;
}
int Min = N;
for(int i=head[u];i!= -1;i=edge[i].next)
if(edge[i].cap-edge[i].flow&&dep[edge[i].to]<Min){
Min=dep[edge[i].to];
cur[u] = i;
}
gap[dep[u]]--;
if(!gap[dep[u]]) return ans;
dep[u] = Min +1;
gap[dep[u]]++;
if(u!=start) u = edge[pre[u]^1].to;
}
return ans;
}
//最大流结束
//构图
void build(int mid){
int i,j;
S=TOL+1;
V=TOL+2;
//超级源点 到每个人
for(i=0;i<M;i++){
addedge(S,i,b[i]);
}
//每场比赛到超级汇点
for(i=0;i<M;i++){
for(j=i+1;j<M;j++){
addedge(co[i][j],V,1);
}
}
//人到比赛
for(i=0;i<M;i++){
for(j=i+1;j<M;j++){
if(i<mid&&j<mid){
if(b[i]>b[j]){
addedge(j,co[i][j],1);
}
else if(b[i]<b[j]){
addedge(i,co[i][j],1);
}
else{
addedge(j,co[i][j],1);
addedge(i,co[i][j],1);
}
}
else{
addedge(j,co[i][j],1);
addedge(i,co[i][j],1);
}
}
}
}
//二分枚举解题
bool solve(int mid){
init();
build(mid);
int k=sap(S,V,V+1);
// printf("k=%d\n",k);
return k==TOL-M+1;
}
int main(){
int i,j,k,l,m,n;
int T;
scanf("%d\n",&T);
char a;
while(T--){
i=0;
while(1){
scanf("%c",&a);
if(a=='\n'||a=='\0'){
break;
}
else{
if(a!=' '){
b[i++]=a-'0';
}
}
}
//printf("%d\n",b[0]);
M=i;
sort(b,b+M,cmp);
int num=M;
// printf("M= %d\n",M);
for(i=0;i<M;i++){
for(j=i+1;j<M;j++){
co[i][j]=num++;
}
}
TOL=num-1;
// printf("TOL= %d\n",TOL);
// for(int aa=0;aa<M;aa++) printf("%d ",b[aa]);
int l=0,orz;
for(i=1;i<=M;i++){
if(solve(i)){
orz=i;
}
else break;
}
printf("%d\n",orz);
}
}
相关文章推荐
- 动易2006序列号破解算法公布
- Ruby实现的矩阵连乘算法
- C#插入法排序算法实例分析
- 超大数据量存储常用数据库分表分库算法总结
- C#数据结构与算法揭秘二
- C#冒泡法排序算法实例分析
- 算法练习之从String.indexOf的模拟实现开始
- C#算法之关于大牛生小牛的问题
- C#实现的算24点游戏算法实例分析
- c语言实现的带通配符匹配算法
- 浅析STL中的常用算法
- 算法之排列算法与组合算法详解
- C++实现一维向量旋转算法
- Ruby实现的合并排序算法
- C#折半插入排序算法实现方法
- 基于C++实现的各种内部排序算法汇总
- C++线性时间的排序算法分析
- C++实现汉诺塔算法经典实例
- PHP实现克鲁斯卡尔算法实例解析
- C#获取关键字附近文字算法实例