洛谷P2765魔术球问题 最小路径覆盖
https://www.luogu.org/problemnew/show/P2765
看到这一题第一眼想到:这不是二分最大流吗,后来发现还有一种更快的方法。
首先如果知道要放多少个球求最少的柱子,很显然是一道最小点路径覆盖的题,将一个点拆成u,v两个点,u和S相连,v和T相连,之后的有向边i,就用ui和vj相连即可。
但是这题首先不知道有多少个球,所以考虑依次加入点以及和这个点相关的边,然后在残余网络上跑新的最大流,如果可以跑出流量来意味着这个点成功在现有的柱子上按排上了,如果跑不出来说明按排不上,需要重新开一根柱子放这个点。
直到跑到答案k的时候,柱子数超过了n,要的答案就是k - 1,至于方案,只要在最后的残余网络图上面搜索一下每个点的前驱即可。
#include <map>
#include <set>
#include <ctime>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
#define For(i, x, y) for(int i=x;i<=y;i++)
#define _For(i, x, y) for(int i=x;i>=y;i--)
#define Mem(f, x) memset(f,x,sizeof(f))
#define Sca(x) scanf("%d", &x)
#define Sca2(x,y) scanf("%d%d",&x,&y)
#define Sca3(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define Scl(x) scanf("%lld",&x);
#define Pri(x) printf("%d\n", x)
#define Prl(x) printf("%lld\n",x);
#define CLR(u) for(int i=0;i<=N;i++)u[i].clear();
#define LL long long
#define ULL unsigned long long
#define mp make_pair
#define PII pair<int,int>
#define PIL pair<int,long long>
#define PLL pair<long long,long long>
#define pb push_back
#define fi first
#define se second
typedef vector<int> VI;
int read(){int x = ,f = ;char c = getchar();while (c<'' || c>''){if (c == '-') f = -;c = getchar();}
while (c >= ''&&c <= ''){x = x * + c - '';c = getchar();}return x*f;}
const double eps = 1e-;
const int maxn = ;
const int maxm = ;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + ;
int N,M,K;
int a[maxn];
struct Edge{
int to,next,cap,flow;
Edge(){}
Edge(int to,int next,int cap,int flow):to(to),next(next),cap(cap),flow(flow){}
}edge[maxm * ];
int head[maxn * ],dis[maxn * ],pre[maxn * ],nxt[maxn * ],vis[maxn * ];
int n,s,tot,t;
void init(int N,int S,int T){
n = N;s = S;t = T;
for(int i = ; i <= n ; i ++) head[i] = -;
tot = ;
}
void add(int u,int v,int w){
edge[tot] = Edge(v,head[u],w,);
head[u] = tot++;
edge[tot] = Edge(u,head[v],,);
head[v] = tot++;
}
bool BFS(){
for(int i = ; i <= n; i ++) dis[i] = -;
queue<int>Q;
dis[s] = ; Q.push(s);
while(!Q.empty()){
int u = Q.front(); Q.pop();
for(int i = head[u]; ~i ; i = edge[i].next){
int v = edge[i].to;
if(~dis[v] || edge[i].cap <= edge[i].flow) continue;
dis[v] = dis[u] + ;
Q.push(v);
}
}
return ~dis[t];
}
int dfs(int u,int a){
if(u == t || !a) return a;
int flow = ;
for(int &i = pre[u]; ~i ; i = edge[i].next){
int v = edge[i].to;
if(dis[u] + != dis[v]) continue;
int f = dfs(v,min(a,edge[i].cap - edge[i].flow));
if(!f) continue;
a -= f; flow += f;
edge[i].flow += f;
edge[i ^ ].flow -= f;
}
return flow;
}
int maxflow(){
int flow = ;
while(BFS()){
for(int i = ; i <= n ; i ++) pre[i] = head[i];
flow += dfs(s,INF);
}
return flow;
}
void search(int t){
for(int i = ; i <= t; i ++){
for(int j = head[i]; ~j ; j = edge[j].next){
int v = edge[j].to;
if(v == s) continue;
if(edge[j].flow){
nxt[i] = v - maxn;
vis[v - maxn] = ;
}
}
}
for(int i = ; i <= t; i ++){
if(!vis[i]){
for(int j = i; j; j = nxt[j]){
printf("%d ",j);
}
puts("");
}
}
}
int main(){
Sca(N);
for(int i = ; i <= ; i ++) a[i] = i * i;
int S = ,T = ;
init(,S,T);
int num = ,k;
int cnt = ;
for(k = ;num <= N; k ++){
while(k + k > a[cnt + ]) cnt++;
add(S,k,);
add(k + maxn,T,);
for(int i = cnt ; i >= ; i --){
if(a[i] - k <= ) break;
add(a[i] - k,k + maxn,);
}
if(!maxflow()) num++;
}
k-=; num--;
Pri(k);
search(k);
return ;
}
洛谷P2765魔术球问题 最小路径覆盖的更多相关文章
- luogu P2765 魔术球问题 (最小路径覆盖)
大意:给定n根柱子, 依次放入1,2,3,...的球, 同一根柱子相邻两个球和为完全平方数, 求最多放多少个球. 对和为平方数的点连边, 就相当于求DAG上最小路径覆盖. #include <i ...
- 洛谷 P2765 魔术球问题 (dinic求最大流,最小边覆盖)
P2765 魔术球问题 题目描述 «问题描述: 假设有n根柱子,现要按下述规则在这n根柱子中依次放入编号为1,2,3,...的球. (1)每次只能在某根柱子的最上面放球. (2)在同一根柱子中,任何2 ...
- 洛谷 P2765 魔术球问题 解题报告
P2765 魔术球问题 题目描述 问题描述: 假设有\(n\)根柱子,现要按下述规则在这\(n\)根柱子中依次放入编号为\(1,2,3,\dots\)的球. \((1)\) 每次只能在某根柱子的最上面 ...
- 洛谷 [P2765] 魔术球问题
贪心做法 每次尽可能选择已经放过球的柱子 #include <iostream> #include <cstdio> #include <cstring> #inc ...
- [loj #6003]「网络流 24 题」魔术球 二分图最小路径覆盖,网络流
#6003. 「网络流 24 题」魔术球 内存限制:256 MiB时间限制:1000 ms标准输入输出 题目类型:传统评测方式:Special Judge 上传者: 匿名 提交提交记录统计讨论测试数据 ...
- 洛谷P2765 魔术球问题(最大流)
传送门 %%%KSkun大佬 话说明明是网络流……这题竟然还有打表找规律和纯贪心AC的……都是神犇啊…… 来说一下如何建图.首先把每一个点拆成$X_i$和$Y_i$,然后$S$向$X_i$连一条容量为 ...
- 洛谷P2765 魔术球问题(贪心 最大流)
题意 已经很简洁了吧. 假设有n根柱子,现要按下述规则在这n根柱子中依次放入编号为1,2,3,...的球. (1)每次只能在某根柱子的最上面放球. (2)在同一根柱子中,任何2个相邻球的编号之和为完全 ...
- 洛谷P2765 魔术球问题
题目链接:https://www.luogu.org/problemnew/show/P2765 知识点: 最大流 解题思路: 本题所有边的容量均为 \(1\). 从 \(1\) 开始加入数字,将这个 ...
- 洛谷 P3187 BZOJ 1185 [HNOI2007]最小矩形覆盖 (旋转卡壳)
题目链接: 洛谷 P3187 [HNOI2007]最小矩形覆盖 BZOJ 1185: [HNOI2007]最小矩形覆盖 Description 给定一些点的坐标,要求求能够覆盖所有点的最小面积的矩形, ...
随机推荐
- How to execute a Stored Procedure with Entity Framework Code First
Recently I worked on a project, which I started as code first and then I forced to switch to Databas ...
- 清北学堂(2019 4 28 ) part 2
主要内容数据结构: 1.二叉搜索树 一棵二叉树,对于包括根节点在内的节点,所有该节点左儿子比此节点小,所有该节点右儿子比该节点大,(感觉好像二分...) 每个节点包含一个指向父亲的指针,和两个指向儿子 ...
- Codeforces518 D. Ilya and Escalator
传送门:>Here< 题意:有n个人排队做电梯,每个人必须等前面的人全部上了以后才能上.对于每秒钟,有p的概率选择上电梯,(1-p)的概率选择不上电梯.现在问t秒期望多少人上电梯 解题思路 ...
- PhoneGap & Cordova 安装白皮书
1.前题: PhoneGap是一个用基于HTML,CSS和JavaScript的,创建移动跨平台移动应用程序的快速开发平台.它使开发者能够利用 iPhone,Android,Palm,Symbian, ...
- android Button 属性
Android中button 继承了TextView组件. 可以这么用: final TextView tv = new Button(getApplicationContext()); tv.set ...
- 【BZOJ5211】[ZJOI2018]线图(树哈希,动态规划)
[BZOJ5211][ZJOI2018]线图(树哈希,动态规划) 题面 BZOJ 洛谷 题解 吉老师的题目是真的神仙啊. 去年去现场这题似乎骗了\(20\)分就滚粗了? 首先\(k=2\)直接算\(k ...
- 【BZOJ4771】七彩树(主席树)
[BZOJ4771]七彩树(主席树) 题面 BZOJ 题解 如果没有深度限制,每次只询问子树内的颜色个数,除了树套树\(dfs\)序加前驱或者后继强行二维数点之外,还有这样一种做法: 把所有相同颜色的 ...
- vue路由原理剖析
单页面应用(SPA)的核心之一是: 更新视图而不重新请求页面, 实现这一点主要是两种方式: 1.Hash: 通过改变hash值 2.History: 利用history对象新特性(详情可出门左拐见: ...
- 152. Maximum Product Subarray 以及 讨论【最大连续子序列】
题目大意: 连续最大子段积 题目思路: 最大值只能产生在一个正数x一个正数,一个负数乘一个负数,所以维护两个值,一个区间最大值,一个最小值 其他的话: 在讨论这个问题之前,我先来说一说大一刚开学就学了 ...
- Equivalent Sets HDU - 3836 (Tarjan)
题目说给出一些子集,如果A是B的子集,B是A的子集,那么A和B就是相等的,然后给出n个集合m个关系,m个关系表示u是v的子集,问你最小再添加多少个关系可以让这n个集合都是相等的 如果这n个几个都是互相 ...