高嘉煊讲的杂题;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的更多相关文章

  1. CodeChef:Chef and Problems(分块)

    CodeChef:Chef and Problems 题目大意 有一个长度为n的序列$a_1,a_2,……,a_n$,每次给出一个区间[l,r],求在区间内两个相等的数的最远距离($max(j-i,满 ...

  2. CODECHEF Chef and Churus 解题报告

    [CODECHEF]Chef and Churus Description 有一个长度为\(n\)的数组\(A\),有\(n\)个函数,第\(i\)个函数的值为\(\sum_{j=l_i}^{r_i} ...

  3. 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 ...

  4. 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]) ...

  5. CodeChef Chef and Churu [分块]

    题意: 单点修改$a$ 询问$a$的区间和$f$的区间和 原来普通计算机是这道题改编的吧... 对$f$分块,预处理$c[i][j]$为块i中$a_j$出现几次,$O(NH(N))$,只要每个块差分加 ...

  6. codechef Chef And Easy Xor Queries

    做法:我们考虑前缀异或和,修改操作就变成了区间[i,n]都异或x 查询操作就变成了:区间[1,x]中有几个k 显然的分块,每个块打一个tag标记表示这个块中所有的元素都异或了tag[x] 然后处理出这 ...

  7. 2019.02.14 codechef Chef at the Food Fair(线段树+泰勒展开)

    传送门 题意:现在有nnn个位置,每个位置上有一个值aia_iai​. 要求支持如下两种操作: 区间乘vvv 求区间的(1−ai)(1-a_i)(1−ai​)之积 思路: 考虑转换式子: Ans=∏i ...

  8. codechef Chef and Problems

    终于补出这道:一直耽搁到现在 找到一个代码可读性很好的分块temp; 题意:给一个长度为n 的数组 A,Q次询问,区间相等数的最大范围是多少? 数据范围都是10e5; 当然知道分块了: 传统分块看各种 ...

  9. Codechef Chef Cuts Tree

    该思博的时候就思博到底,套路的时候不能再套路的一道题 首先我们将联通块的大小平方和进行转化,发现它就等价于连通点对数,而这个可以转化为连接两点的边数(距离)和 所以我们考虑第\(i\)天时,一个点对\ ...

随机推荐

  1. [转]jQuery为控件添加水印文字

    本文转自:http://www.cnblogs.com/gzh4455/archive/2011/09/29/2195418.html jQuery扩展: jquery.tinywatermark-3 ...

  2. Python collections

    #count对象 Only 2.7 from collections import Counter #统计字母出现的次数 Counter('hello world') Counter(['red', ...

  3. MATLAB线性回归方程与非线性回归方程的相关计算

    每次比赛都需要查一下,这次直接总结到自己的博客中. 以这个为例子: 2.线性方程的相关计算 x=[1,2,3,4,5]';%参数矩阵 X=[ones(5,1),x];%产生一个5行一列的矩阵,后接x矩 ...

  4. mongodb开机启动

    #!/bin/bash # #chkconfig: #description: mongodb start() { /usr/local/mongodb/bin/mongod --dbpath=/us ...

  5. 位运算(1)——Hamming Distance

    https://leetcode.com/problems/hamming-distance/#/description 输入:两个整数x,y,且0 ≤ x, y < 231. 输出:x,y的二 ...

  6. yield关键字的使用

    yield的中文是什么意思呢? 在金山词霸上面的翻译是: vt.屈服,投降: 生产: 获利: 不再反对 vi.放弃,屈服: 生利: 退让,退位 n.产量,产额: 投资的收益: 屈服,击穿: 产品 个人 ...

  7. Ienumerable和Ienumerator的使用

    using UnityEngine; using System.Collections; public class TestCoroutine : MonoBehaviour { void Start ...

  8. 《ArcGIS Runtime SDK for Android开发笔记》——(1)、Android Studio下载与安装

    1.前言 Android Studio 是一个Android开发环境,基于IntelliJ IDEA. 类似 Eclipse ADT,Android Studio 提供了集成的 Android 开发工 ...

  9. 【Angular JS】网站使用社会化评论插件,以及过程中碰到的坑

    目前正在开发自己的网站,技术上使用Angular JS + Express JS + Mongo DB.由于网站会有文章发布,因此需要有评论功能.评论功能也可以自己开发,但由于现在社会化评论插件很多, ...

  10. 爆料!如何在Visual Studio 2017上体验五星级云服务

    2017 年 3 月初,号称宇宙最强 IDE 之一的 Visual Studio 发布了最新的 2017 版本,遥想自己使用 VC++ 6.0 的当年,看着现在已然稀疏的头发,真是一入 IT 似海深, ...