【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\)天时,一个点对\ ...
随机推荐
- 硬盘和显卡的访问与控制(三)——《x86汇编语言:从实模式到保护模式》读书笔记03
上一篇博文我们用了很大的篇幅说了加载器,这一篇我们该说说用户程序了. 先看作者的源码吧. ;代码清单8-2 ;文件名:c08.asm ;文件说明:用户程序 ;创建日期:2011-5-5 18:17 ; ...
- 《C#高效编程》读书笔记13-正确的初始化静态成员变量
在创建某个类型实例之前,就应该初始化该实例的所有静态成员变量.而C#为此提供了静态初始化器和静态构造函数. 静态构造函数是特殊的构造函数,将在其他所有方法执行之前以及变量或属性被第一次访问之前执行. ...
- spring 类注入失败,解决之道
1.今天偶尔发现的问题,如果你在一个类上面用了注解@Async,spring的异步注解之后,发现如果别的类用@Autowired导入这个类时会失败! 解决办法:用了@Async无非是想方便的用异步操作 ...
- BZOJ4260: Codechef REBXOR (01Tire树)
题意 题目链接 Sol 首先维护出前缀xor和后缀xor 对每个位置的元素插入到Trie树里面,每次找到和该前缀xor起来最大的元素 正反各做一遍,取最大. 记得要开log倍空间qwq.. #incl ...
- C++ Knowledge series Inheritance & RTTI & Exception Handling
Inheritance The pointer or reference to base class can address/be assigned with any of the classes d ...
- ArcSDE空间数据库中SDE用户使用探讨(转)
ArcSDE作为空间数据库解决方案,应用非常广泛,本短文将尝试描述SDE的工作机制,简要说明空间数据 库中SDE用户的使用方法. ArcSDE如何工作 ArcSDE属于中间件技术,其本身并不能够存储空 ...
- Azure:陪伴你们,是我最长情的告白
立即访问http://market.azure.cn
- Servlet是线程安全的吗?
Servlet不是线程安全的. 要解释为什么Servlet为什么不是线程安全的,需要了解Servlet容器(即Tomcat)使如何响应HTTP请求的. 当Tomcat接收到Client的HTTP请求时 ...
- Eclipse Push出现rejected - non-fast-forward错误
在 Push到服务器时有时会出现 rejected - non-fast-forward 错误,这是由于pull的代码而远端发生改变,此时再提交之前你需要将远端的改变合并到本地上 参考:https:/ ...
- MVC学习笔记:MVC实现用户登录验证ActionFilterAttribute用法并实现统一授权
在项目下新建一个文件夹来专门放过滤器类,首先创建一个类LoginFilter,这个类继承ActionFilterAttribute.用来检查用户是否登录和用户权限.: using System; us ...