【A* 网络流】codechef Chef and Cut
高嘉煊讲的杂题;A*和网络流的练手题
题目大意
https://s3.amazonaws.com/codechef_shared/download/translated/SEPT16/mandarin/CHEFKC.pdf
一张有向带权图,固定$S$和$T$,求权值第$k$小的割。
$n \le 77,m\le 777,k \le 777$
题目分析
考虑如何描述每一种割:$p_i=1$表示$S$与$i$连通;$p_i=0$表示$i$与$T$连通。注意到这里的$\{p_i\}$与每种割是一一对应的,那么就可以以$p_i$为状态进行A*扩展求第$k$大状态。
接下去的问题就是如何计算$\{p_i\}$的权值。那么对于$p_i=1$,连边$(S,i,INF)$表示$(S,i)$无法割去;$p_i=0$同理。对于这张图做最小流即可。
最后可能是一个A*不同写法上的技巧。讲课时候讲的是一个状态$(len,\{p_i\},val)$表示只确认前$len$位的状态$p_i$的权值$val$。这种扩展是每次一步步确认元素,时空效率都不高。另一种写法直接$(len,\{p_i\},val)$表示$n$个点的状态为$\{p_i\}$,确定不改变 前$len$个元素,这个情况下的权值$val$。每次转移的时候,枚举新状态确认的长度$len'=len+1\cdots n$,保留前$len'-1$个状态并将$len'$位取反(这个处理是为了保证不重不漏遍历所有状态),然后以此状态处理出的最小割作为新的状态,这样就能保证省略很多中途步骤的无用状态而直接取当前状态的最优方案(因为既然要按顺序,那么必定从每个子状态的最优状态再进一步考虑)。
反正效率还不错,cc榜rk4.
1A还行
#include<bits/stdc++.h>
typedef long long ll;
const int maxn = ;
const int maxm = ;
const int INF = 1e9; struct Edge
{
int u,v,f,c;
Edge(int a=, int b=, int c=, int d=):u(a),v(b),f(c),c(d) {}
}edges[maxm],sv[maxm];
struct node
{
int len,val;
bool a[maxn];
bool operator < (node a) const
{
return val > a.val;
}
void init(){memset(a, , sizeof a);}
}tmp,trans;
bool vis[maxn];
int n,m,k,S,T,sta,end;
int edgeTot,head[maxn],nxt[maxm],lv[maxn];
std::priority_queue<node> q; void addedge(int u, int v, int c)
{
edges[edgeTot] = Edge(u, v, , c), nxt[edgeTot] = head[u], head[u] = edgeTot, ++edgeTot;
edges[edgeTot] = Edge(v, u, , ), nxt[edgeTot] = head[v], head[v] = edgeTot, ++edgeTot;
}
bool buildLevel()
{
std::queue<int> q;
memset(lv, , sizeof lv);
q.push(S), lv[S] = ;
for (int tmp; q.size(); )
{
tmp = q.front(), q.pop();
for (int i=head[tmp]; i!=-; i=nxt[i])
{
int v = edges[i].v;
if (edges[i].f < edges[i].c&&!lv[v]){
lv[v] = lv[tmp]+, q.push(v);
if (v==T) return true;
}
}
}
return false;
}
int fndPath(int x, int lim)
{
if (!lim||x==T) return lim;
int sum = ;
for (int i=head[x]; i!=-&&sum < lim; i=nxt[i])
{
int v = edges[i].v, val = ;
if (lv[v]==lv[x]+&&edges[i].f < edges[i].c){
if ((val = fndPath(v, std::min(edges[i].c-edges[i].f, lim-sum)))){
sum += val, edges[i].f += val, edges[i^].f -= val;
}else lv[v] = -;
}
}
return sum;
}
int dinic()
{
int ret = , val = ;
while (buildLevel())
while ((val = fndPath(S, INF))) ret += val;
return ret;
}
void calc(node &x)
{
memset(head, -, sizeof head), edgeTot = ;
for (int i=; i<=m; i++) addedge(sv[i].u, sv[i].v, sv[i].c);
addedge(S, sta, INF), addedge(end, T, INF);
for (int i=; i<=x.len; i++)
if (x.a[i]) addedge(S, i, INF);
else addedge(i, T, INF);
std::queue<int> q;
x.val = dinic(), q.push(S);
memset(vis, , sizeof vis);
for (int i=; i<=n; i++) x.a[i] = ;
for (int tmp; q.size(); )
{
tmp = q.front(), q.pop();
for (int i=head[tmp]; i!=-; i=nxt[i])
if (edges[i].f < edges[i].c){
int v = edges[i].v;
if (!vis[v]) vis[v] = true, x.a[v] = , q.push(v);
}
}
}
int main()
{
freopen("CHEFKC.in","r",stdin);
freopen("CHEFKC.out","w",stdout);
scanf("%d%d%d%d%d",&n,&m,&k,&sta,&end), S = , T = n+;
for (int i=; i<=m; i++) scanf("%d%d%d",&sv[i].u,&sv[i].v,&sv[i].c);
tmp.len = , tmp.a[sta] = true, calc(tmp), q.push(tmp);
while (--k)
{
tmp = q.top(), q.pop();
for (int i=tmp.len+; i<=n; i++)
{
trans.init(), trans.len = i, trans.a[i] = !tmp.a[i];
for (int j=; j<i; j++) trans.a[j] = tmp.a[j];
calc(trans), q.push(trans);
}
}
printf("%d\n",q.top().val);
return ;
}
END
【A* 网络流】codechef Chef and Cut的更多相关文章
- CodeChef:Chef and Problems(分块)
CodeChef:Chef and Problems 题目大意 有一个长度为n的序列$a_1,a_2,……,a_n$,每次给出一个区间[l,r],求在区间内两个相等的数的最远距离($max(j-i,满 ...
- CODECHEF Chef and Churus 解题报告
[CODECHEF]Chef and Churus Description 有一个长度为\(n\)的数组\(A\),有\(n\)个函数,第\(i\)个函数的值为\(\sum_{j=l_i}^{r_i} ...
- codechef Chef and The Right Triangles 题解
Chef and The Right Triangles The Chef is given a list of N triangles. Each triangle is identfied by ...
- Codechef Chef and Triangles(离散化+区间并集)
题目链接 Chef and Triangles 先排序,然后得到$m - 1$个区间: $(a[2] - a[1], a[2] + a[1])$ $(a[3] - a[2], a[3] + a[2]) ...
- CodeChef Chef and Churu [分块]
题意: 单点修改$a$ 询问$a$的区间和$f$的区间和 原来普通计算机是这道题改编的吧... 对$f$分块,预处理$c[i][j]$为块i中$a_j$出现几次,$O(NH(N))$,只要每个块差分加 ...
- codechef Chef And Easy Xor Queries
做法:我们考虑前缀异或和,修改操作就变成了区间[i,n]都异或x 查询操作就变成了:区间[1,x]中有几个k 显然的分块,每个块打一个tag标记表示这个块中所有的元素都异或了tag[x] 然后处理出这 ...
- 2019.02.14 codechef Chef at the Food Fair(线段树+泰勒展开)
传送门 题意:现在有nnn个位置,每个位置上有一个值aia_iai. 要求支持如下两种操作: 区间乘vvv 求区间的(1−ai)(1-a_i)(1−ai)之积 思路: 考虑转换式子: Ans=∏i ...
- codechef Chef and Problems
终于补出这道:一直耽搁到现在 找到一个代码可读性很好的分块temp; 题意:给一个长度为n 的数组 A,Q次询问,区间相等数的最大范围是多少? 数据范围都是10e5; 当然知道分块了: 传统分块看各种 ...
- Codechef Chef Cuts Tree
该思博的时候就思博到底,套路的时候不能再套路的一道题 首先我们将联通块的大小平方和进行转化,发现它就等价于连通点对数,而这个可以转化为连接两点的边数(距离)和 所以我们考虑第\(i\)天时,一个点对\ ...
随机推荐
- web service, wcf, wcf rest, web api之间的区别
在.NET Framework中,有很多种技术可以创建基于http协议的服务,譬如说web service, wcf,wcf rest和web api等等.网上有很多的文章教我们如何开发.使用这几种技 ...
- React.js 小书 Lesson7 - 组件的 render 方法
作者:胡子大哈 原文链接:http://huziketang.com/books/react/lesson7 转载请注明出处,保留原文链接和作者信息. React.js 中一切皆组件,用 React. ...
- Python的历史与基本知识入门
一.Python简介 1.1989年由"龟叔"Guido van Rossum在圣诞节期间打发无聊时间编写. 2.Python是一门弱类型解释性语言. 3.优点:代码简洁,明确,优 ...
- u-boot分析(二)----工作流程分析
u-boot分析(二) 由于这两天家里有点事,所以耽误了点时间,没有按时更新,今天我首先要跟大家说说我对于u-boot分析的整体的思路,然后呢我以后的博客会按照这个内容更新,希望大家关注. 言归正传, ...
- [SVN]TortoiseSVN工具培训3─使用基本流程和图标说明
1.SVN的使用基本流程 注意:对于文件编辑方面,上图的编辑副本操作前建议进行Get lock操作,以防出现后续的冲突等异常报错. 2.SVN的基本图标说明
- 初看Mybatis 源码 (一)
Mybatis 的使用,首先需要构建一个SqlSessionFactory 实例.而该实例可以通过SqlSessionFactoryBuilder来创建. String resource = &quo ...
- php中增删改查以及返回结果(一)
虽然毕业后找的第一份正式的工作并不那么令人满意,但是在度过最初的迷茫期后,自己还是决定成为一个程序猿. 最近也是利用上班偶尔闲下来的时间,开始看书,撸代码,写一些小程序. 这两个礼拜主要的写的都是有关 ...
- IDEA下通过Git实现代码管理
IDEA下通过Git实现代码管理 1.介绍 1.1 Git概述 Git是类似于SVN等代码管理软件,使用分布式技术实现.Github是互联网代码仓库,每个人可以在上面创建自己的仓库,使用git完成同g ...
- dd-wrt ddns更新失败由于电信提供的ip不是公网ip
由于电信提供的ip地址原来是公网的ip,后来电信通过nat提供一个内网ip,导致ddns更新失败.电话给电信客服10000号,让他们修改回来之后就可以了. 如果ddns更新失败,尤其是原本是正常的,后 ...
- nutzwk运行后wk-web中生成ehcache.disk.store.dir有什么用,怎么去掉
nutzwk运行后wk-web中生成ehcache.disk.store.dir有什么用,怎么去掉 发布于 29天前 作者 qq_96c46988 64 次浏览 复制 上一个帖子 下一个帖 ...