洛谷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 给定一些点的坐标,要求求能够覆盖所有点的最小面积的矩形, ...
随机推荐
- 51nod2383
2383 高维部分和 1 秒 131,072 KB 80 分 5 级题 输入一个长度为n的数组a[i],下标从0开始(0到n-1)保证n是2的整数次幂,对于每个i (0 <= i < ...
- Wiener Filter
假设分别有两个WSS process:$x[n]$,$y[n]$,这两个process之间存在某种关系,并且我们也了解这种关系.现在我们手头上有process $x[n]$,目的是要设计一个LTI系统 ...
- Tyche 2147 旅行
题目描述 你有m元钱,将要游览n个国家.每一个国家有一种商品,其中第i个国家商品的单价为ai元.每到一个国家,你会用手上的钱疯狂购买这个国家的商品,直到剩余的钱无法购买为止. 现在你要决定游览这n个国 ...
- ElasticSearch查询 第四篇:匹配查询(Match)
<ElasticSearch查询>目录导航: ElasticSearch查询 第一篇:搜索API ElasticSearch查询 第二篇:文档更新 ElasticSearch查询 第三篇: ...
- pip 解决下载包速度慢的问题
对于Python开发用户来讲,PIP安装软件包是家常便饭.但国外的源下载速度实在太慢,浪费时间.而且经常出现下载后安装出错问题.所以把PIP安装源替换成国内镜像,可以大幅提升下载速度,还可以提高安装成 ...
- 洛谷P1622释放囚犯
题目: 这个题很明显是一个区间DP,但是比较不同的是,这个题它很像区间DP的经典题——石子合并. 然后我傻傻的搞了这个题搞了一下午,然后几乎看遍了全网的题解,就只看懂了这个方法,可能是我太菜了吧,但是 ...
- BZOJ 1912 巡逻(算竞进阶习题)
树的直径 这题如果k=1很简单,就是在树的最长链上加个环,这样就最大化的减少重复的路程 但是k=2的时候需要考虑两个环的重叠部分,如果没有重叠部分,则和k=1的情况是一样的,但是假如有重叠部分,我们可 ...
- LOJ2255. 「SNOI2017」炸弹 (线段树)
本文为线段树做法 (听说可以tarjan缩点+拓扑? 感觉差不多..而且这样看起来方便很多 找到左端点的过程可以看作 点 -> 区间内lowerbound最小的点 -> lowerboun ...
- Codeforces 700 C. Break Up(Tarjan求桥)
题意 给你一个有 \(n\) 个点, \(m\) 条边的无向图,每条有边权 \(w_i\) ,现在要选择至多两条边断开,使得 \(S, T\) 不连通,并且使得边权和尽量小. \(n \le 1000 ...
- iis express添加虚拟目录
在调试WEB时,还是使用IIS EXPRESS比较方便, 在IIS中,选择网站,右击,添加虚拟目录或者应用程序,就能添加虚拟目录了.. 在IIS EXPRESS中,添加虚拟目录如下 1.右击IIS E ...