POJ2669不错的最大流 竞赛问题(枚举King的个数)
题意:
有n个人,任意两个人都比一次赛(一共比了n*(n-1)/2场),赢一场得到一分,最后的时候如果得分最高,或者是自己打败了所有比自己得分都高的人就算是King,给你每个人的最后得分,问最多有多少个人是King.
思路:
一开始上了就贪心了一次,WA了,改了改之后又贪心了一次,还是没过,然后换思路(其实做这个题目是本着最大流来的),然后就去考虑最大流,最大流的话也比较容易理解,关键是枚举的时候有点说道,先说下建图,把每个人看成一个点,然后把每场比赛看成一个点,源点连接所有人,流量为得分,所有比赛连接汇点,流量1,说到这估计大多数都能建图了吧,接着说,然后就是对于那些King的点,如果和他相关的比赛节点中的另一个点比他分高,那么他一定要赢这场比赛,那么他连接这场比赛的点,否则的话就是不确定,谁赢都行,那么和这场比赛相关的两个点都连接这场比赛就行了,最多11个人左右吧,那么可以直接枚举谁是King,最保守而且没争议的方法就是暴力搜索枚举,就是01枚举,2^10*最大流时间,这个完全可以接受,然后就是网上说的那种直接枚举个数的说法,这个说法要明确一个问题,那就是如果当前有m个King,那么这m个不一定必须是后m个,也可以是中间的一些个,但是按照结论反推可以知道,这m个可以是后m个,也就是说即使不是后m个也可以转换成后m个,所以直接枚举后m就行,关键是要明白不是后m个是怎么可以转换成后m个的,我的想法一开始是找两个点,假设1..i..j..n,假如i是King,而j不是,那么就想办法吧ij的关系调换,就是让i变成不是King,而j是King,按照结论反推肯定是可以调换的,但是我想了很多方法都没有平衡掉ij之间的数字,找网上的也没有可以让我信服的,但是我自己有一个猜想,那就是我感觉可以按照贪心的方式去理解,越往后的称为King的代价就越小,也就是消耗的总的固定流量就越小,那么当然是越往后越可能了,枚举当然那是从后面开始,还有一个问题就是我感觉如果当前序列有k个可以称为King的话,那么一定可以转换成后k个,但是如果当前是后k个的话,不一定能往前转换,也就是我感觉后k个是最优的选择,就是类似那种后k个可以,但是还余出来一些资源没用,通过这些资源可以吧后k个中的一些挪到前面来,这样就产生了答案不以为的情况,但是直接枚举后k个是最优的方式,所有是正确的,这个也只是自己的感觉而已,已过想证明必须要把得分平衡掉。。。。下面是两种方法的代码,我的流用的是DINIC,估计姿势不优吧,速度和网上别人的速度比慢了很多.
DFS+DINIC
#include<queue>
#include<stdio.h>
#include<string.h>
#define N_node 150
#define N_edge 5000
#define INF 1000000000
using namespace std;
typedef struct
{
int to ,cost ,next;
}STAR;
typedef struct
{
int x ,t;
}DEP;
STAR E[N_edge];
DEP xin ,tou;
int list[N_node] ,listt[N_node] ,tot;
int deep[N_node];
void add(int a ,int b ,int c)
{
E[++tot].to = b;
E[tot].cost = c;
E[tot].next = list[a];
list[a] = tot;
E[++tot].to = a;
E[tot].cost = 0;
E[tot].next = list[b];
list[b] = tot;
}
int minn(int x ,int y)
{
return x < y ? x : y;
}
bool BFS_DEEP(int s ,int t ,int n)
{
memset(deep ,255 ,sizeof(deep));
xin.x = s ,xin.t = 0;
queue<DEP>q;
q.push(xin);
deep[s] = 0;
while(!q.empty())
{
tou = q.front();
q.pop();
for(int k = list[tou.x] ;k ;k = E[k].next)
{
xin.x = E[k].to;
xin.t = tou.t + 1;
if(deep[xin.x] != -1 || !E[k].cost)
continue;
deep[xin.x] = xin.t;
q.push(xin);
}
}
for(int i = 0 ;i <= n ;i ++)
listt[i] = list[i];
return deep[t] != -1;
}
int DFS_Flow(int s ,int t ,int flow)
{
if(s == t) return flow;
int nowflow = 0;
for(int k = listt[s] ;k ;k = E[k].next)
{
listt[s] = k;
int c = E[k].cost;
int to = E[k].to;
if(!c || deep[to] != deep[s] + 1)
continue;
int tmp = DFS_Flow(to ,t ,minn(c ,flow - nowflow));
nowflow += tmp;
E[k].cost -= tmp;
E[k^1].cost += tmp;
if(nowflow == flow) break;
}
if(!nowflow) deep[s] = 0;
return nowflow;
}
int DINIC(int s ,int t ,int n)
{
int ans = 0;
while(BFS_DEEP(s ,t ,n))
{
ans += DFS_Flow(s ,t ,INF);
}
return ans;
}
int now[15] ,num[15];
int Ans ,maxn ,n;
void Flow()
{
memset(list ,0 ,sizeof(list));
tot = 1;
for(int i = 1 ;i <= n ;i ++)
add(0 ,i ,num[i]);
int nowid = n;
for(int i = 1 ;i <= n ;i ++)
for(int j = i + 1 ;j <= n ;j ++)
{
++nowid;
if(num[i] < num[j] && now[i])
add(i ,nowid ,1);
else if(num[j] < num[i] && now[j])
add(j ,nowid ,1);
else add(i ,nowid ,1) ,add(j ,nowid ,1);
add(nowid ,n + n * (n - 1) / 2 + 1 ,1);
}
int flow = DINIC(0 ,n + n * (n - 1) / 2 + 1 ,n + n * (n - 1) / 2 + 1);
if(flow == n * (n - 1) / 2)
{
int s = 0;
for(int i = 1 ;i <= n ;i ++)
s += now[i];
if(Ans < s) Ans = s;
}
return ;
}
void DFS(int nowid)
{
if(nowid == maxn + 1)
{
Flow();
return;
}
now[nowid] = 0;
DFS(nowid + 1);
now[nowid] = 1;
DFS(nowid + 1);
}
int main ()
{
int t ,i ,nowid;
char str[30];
scanf("%d" ,&t);
getchar();
while(t--)
{
gets(str);
int len = strlen(str);
nowid = 0;
for(i = 0 ;i < len ;i ++)
{
if(str[i] >= '0' && str[i] <= '9')
{
if(i == len - 1 || str[i+1] < '0' || str[i+1] > '9')
num[++nowid] = str[i] - '0';
else
{
num[++nowid] = (str[i] - '0') * 10 + str[i+1] - '0';
i ++;
}
}
}
n = nowid;
for(i = n ;i >= 1 ;i --)
{
if(num[i] == num[n])
{
maxn = i;
now[i] = 1;
}
else now[i] = 0;
}
if(maxn == 1)
{
printf("%d\n" ,n);
continue;
}
Ans = 0;
DFS(1);
printf("%d\n" ,Ans);
}
return 0;
}
枚举后几位+DINIC
#include<queue>
#include<stdio.h>
#include<string.h>
#define N_node 150
#define N_edge 5000
#define INF 1000000000
using namespace std;
typedef struct
{
int to ,cost ,next;
}STAR;
typedef struct
{
int x ,t;
}DEP;
STAR E[N_edge];
DEP xin ,tou;
int list[N_node] ,listt[N_node] ,tot;
int deep[N_node];
int num[15];
void add(int a ,int b ,int c)
{
E[++tot].to = b;
E[tot].cost = c;
E[tot].next = list[a];
list[a] = tot;
E[++tot].to = a;
E[tot].cost = 0;
E[tot].next = list[b];
list[b] = tot;
}
int minn(int x ,int y)
{
return x < y ? x : y;
}
bool BFS_DEEP(int s ,int t ,int n)
{
memset(deep ,255 ,sizeof(deep));
xin.x = s ,xin.t = 0;
queue<DEP>q;
q.push(xin);
deep[s] = 0;
while(!q.empty())
{
tou = q.front();
q.pop();
for(int k = list[tou.x] ;k ;k = E[k].next)
{
xin.x = E[k].to;
xin.t = tou.t + 1;
if(deep[xin.x] != -1 || !E[k].cost)
continue;
deep[xin.x] = xin.t;
q.push(xin);
}
}
for(int i = 0 ;i <= n ;i ++)
listt[i] = list[i];
return deep[t] != -1;
}
int DFS_Flow(int s ,int t ,int flow)
{
if(s == t) return flow;
int nowflow = 0;
for(int k = listt[s] ;k ;k = E[k].next)
{
listt[s] = k;
int c = E[k].cost;
int to = E[k].to;
if(!c || deep[to] != deep[s] + 1)
continue;
int tmp = DFS_Flow(to ,t ,minn(c ,flow - nowflow));
nowflow += tmp;
E[k].cost -= tmp;
E[k^1].cost += tmp;
if(nowflow == flow) break;
}
if(!nowflow) deep[s] = 0;
return nowflow;
}
int DINIC(int s ,int t ,int n)
{
int ans = 0;
while(BFS_DEEP(s ,t ,n))
{
ans += DFS_Flow(s ,t ,INF);
}
return ans;
}
int Flow(int now ,int n)
{
memset(list ,0 ,sizeof(list));
tot = 1;
int s = 0 ,t = n + n * (n - 1) / 2 + 1;
for(int i = 1 ;i <= n ;i ++)
add(s ,i ,num[i]);
int nowid = n;
for(int i = 1 ;i <= n ;i ++)
for(int j = i + 1 ;j <= n ;j ++)
{
++nowid;
if(num[i] < num[j] && i >= now)
add(i ,nowid ,1);
else if(num[j] < num[i] && j >= now)
add(j ,nowid ,1);
else add(i ,nowid ,1) ,add(j ,nowid ,1);
add(nowid ,t ,1);
}
return DINIC(s ,t ,t);
}
int main ()
{
int i ,nowid ,t;
char str[30];
scanf("%d" ,&t);
getchar();
while(t--)
{
gets(str);
int len = strlen(str);
nowid = 0;
for(i = 0 ;i < len ;i ++)
{
if(str[i] >= '0' && str[i] <= '9')
{
if(i == len - 1 || str[i+1] < '0' || str[i + 1] > '9')
num[++nowid] = str[i] - '0';
else
{
num[++nowid] = (str[i] - '0') * 10 + str[i+1] - '0';
i ++;
}
}
}
int list;
for(i = nowid ;i >= 1 ;i --)
if(num[i] == num[nowid]) list = i;
if(list == 1)
{
printf("%d\n" ,nowid);
continue;
}
for(i = 1 ;i <= nowid ;i ++)
{
if(Flow(i ,nowid) == nowid * (nowid - 1) / 2)
break;
}
printf("%d\n" ,nowid - i + 1);
}
return 0;
}
POJ2669不错的最大流 竞赛问题(枚举King的个数)的更多相关文章
- POJ 3185 The Water Bowls(高斯消元-枚举变元个数)
题目链接:http://poj.org/problem?id=3185 题意:20盏灯排成一排.操作第i盏灯的时候,i-1和i+1盏灯的状态均会改变.给定初始状态,问最少操作多少盏灯使得所有灯的状态最 ...
- Educational Codeforces Round 35 B. Two Cakes【枚举/给盘子个数,两份蛋糕块数,最少需要在每个盘子放几块蛋糕保证所有蛋糕块都装下】
B. Two Cakes time limit per test 1 second memory limit per test 256 megabytes input standard input o ...
- hdu 2058 枚举区间和个数
题意: 给你两个数n,m,意思是有一个序列长度n,他是1 2 3 4 ...n,然后让你输出所有连续和等于m的范围. 思路: 是个小水题,随便写几个数字就能发现规律了,我们可以 ...
- POJ2699 The Maximum Number of Strong Kings
Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 2102 Accepted: 975 Description A tour ...
- POJ 2699 The Maximum Number of Strong Kings (最大流+枚举)
http://poj.org/problem?id=2699 题意: 一场联赛可以表示成一个完全图,点表示参赛选手,任意两点u, v之间有且仅有一条有向边(u, v)或( v, u),表示u打败v或v ...
- BNU 33693——Problemsetting——————【枚举+最大流】
Problemsetting Time Limit: 5000ms Memory Limit: 131072KB 64-bit integer IO format: %lld Java cl ...
- poj 2699 The Maximum Number of Strong Kings 枚举 最大流
题目链接 题意 对于一个竞赛图(有向完全图),其顶点是选手,边是比赛,边\(e=(u,v)\)代表该场比赛中\(u\)战胜\(v\). 现定义选手的分数为其战胜的人的个数(即竞赛图中点的出度).并且定 ...
- Spring Cloud Alibaba:Sentinel实现熔断与限流
一.什么是Sentinel Sentinel,中文翻译为哨兵,是为微服务提供流量控制.熔断降级的功能,它和Hystrix提供的功能一样,可以有效的解决微服务调用产生的“雪崩效应”,为微服务系统提供了稳 ...
- 最大流 总结&&做题记录
最近一直很忙,为了节省时间,从今以后的题解会 一个专题 写一篇. 刷了一些题后,有了以下总结: 模型要点: 1.构造流量平衡,在满足流量平衡的情况下,找到要让什么最大. 2.一般用于判断性问题,即所有 ...
随机推荐
- Celery:小试牛刀
Celery是如何工作的? Celery 由于 其分布式体系结构,在某种程度上可能难以理解.下图是典型Django-Celery设置的高级示意图(FROM O'REILLY): 当请求到达时,您可以在 ...
- springboot源码解析-管中窥豹系列之BeanFactoryPostProcessor(十一)
一.前言 Springboot源码解析是一件大工程,逐行逐句的去研究代码,会很枯燥,也不容易坚持下去. 我们不追求大而全,而是试着每次去研究一个小知识点,最终聚沙成塔,这就是我们的springboot ...
- Flink实时计算topN热榜
TopN的常见应用场景,最热商品购买量,最高人气作者的阅读量等等. 1. 用到的知识点 Flink创建kafka数据源: 基于 EventTime 处理,如何指定 Watermark: Flink中的 ...
- 键盘--扫描码--ASCII码--显示器上的字符
在上一篇,我讲了键盘操作会产生扫描码以及如何解析Pause键和Print Screen键的扫描码. 在这一篇,我会说清楚"键盘上的输入为什么会出现在显示器上". 极简版 我们敲击键 ...
- C语言II博客作业02
这个作业属于那个课程 https://edu.cnblogs.com/campus/zswxy/SE2020-4 这个作业要求在哪里 https://edu.cnblogs.com/campus/zs ...
- 用水浒传来学习OKR
用水浒传来学习OKR 目录 用水浒传来学习OKR 0x00 摘要 0x01 OKR 1.1 基本概念 1.2 OKR管理的意义 1.3 Objective 1.3.1 什么是好的O 1.3.2 上下级 ...
- 正则表达式-Python实现
1.概述: Regular Expression.缩写regex,regexp,R等: 正则表达式是文本处理极为重要的工具.用它可以对字符串按照某种规则进行检索,替换. Shell编程和高级编程语言中 ...
- python中类的魔法方法
__xx__这种方法,在Python中均称为魔法方法 1.__init__(self) 该方法的作用是初始化对象 在创建对象时被默认调用,不需要手动调节 self参数不需要开发者传递,解释器会自动将创 ...
- 深入理解Java并发框架AQS系列(三):独占锁(Exclusive Lock)
一.前言 优秀的源码就在那里 经过了前面两章的铺垫,终于要切入正题了,本章也是整个AQS的核心之一 从本章开始,我们要精读AQS源码,在欣赏它的同时也要学会质疑它.当然本文不会带着大家逐行过源码(会有 ...
- [leetcode] 单调栈
本文总结单调栈算法. 原问题 学习一个算法,我们需要清楚的是:这个算法最原始的问题背景是什么样的? 下一个更小元素 给定一个数组 nums,返回每个元素的下一个更小的元素的下标 res,即 res[i ...