高嘉煊讲的杂题;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. MATLAB循环和函数定义,调用

    格式不要括号,最后有end for 循环变量 = 表达式1:表 2:表 3 表1:初值     表2:步长      表3:终值 求圆周率:π/4=1 - 1/3 + 1/5 -1/7+...+(-1 ...

  2. 监听outlook新邮件

    using System; using System.Linq; using Microsoft.Office.Interop.Outlook; using System.Collections.Ge ...

  3. CKEditor4.4.5 插入高度代码及上传图片

    1.首先准备所需要的插件 (1). CKEditor4.4.5  下载地址:http://ckeditor.com/download.如果不想下载直接引用CKEditor的CDN也是可以的.cdn地址 ...

  4. C#本期本周的算法

    C#根据当前时间获取,本周,本月,本季度等时间段 DateTime dt = DateTime.Now; //当前时间 DateTime startWeek = dt.AddDays( - Conve ...

  5. AutoResetEvent 2

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

  6. #与javascript:void(0)的区别

    #"包含了一个位置信息 默认的锚点是#top 也就是网页的上端 而javascript:void(0)  仅仅表示一个死链接 这就是为什么有的时候页面很长浏览链接明明是#可是跳动到了页首 而 ...

  7. tp3.2水印上传文件

    <html> <html lang="en"><head>    <meta charset="UTF-8">  ...

  8. SaaS “可配置”和“多租户”架构的几种技术实现方式

    1.数据存储方式的选择 多租户(Multi-Tenant ),即多个租户共用一个实例,租户的数据既有隔离又有共享,说到底是要解决数据存储的问题. 常用的数据存储方式有三种. 方案一:独立数据库   一 ...

  9. [总结]SHAREPOINT - CAML列表查询(上)

    首先要了解的是CAML(Collaboration Application Markup Language)不仅仅是用在对列表.文档库的查询,字段的定义,站点定义等处处使用的都是CAML. 简单的提一 ...

  10. Movideo SaaS解决方案

    类型: 定制服务 软件包: media solution collateral 联系服务商 产品详情 解决方案 概要 Movideo为媒体客户提供的SaaS解决方案部署在位于全球数据中心的Azure云 ...