Description

                      Special Judge

Hint

  注意是全程不能经过两个相同的景点,并且一天的开始和结束不能用同样的交通方式。


题解

  题目大意:给定两组点,每组有$n$个点,有若干条跨组的有色无向边。求一种方案,包括若干个不相交的连通块,覆盖全部点,每个连通块满足能一笔画(不经过重复的点)并且相邻两次经过的边颜色不相同(开头和结尾经过的边也不能相同)。

  是不是有点类似二分图匹配的问题呢?我们还是考虑用最大流来建图。

  一笔画的时候,每一个经过的点有且只有一条入边,有且只有一条出边,即度数必须为2;两条边的颜色还不能相同。每一个点都如下图所示:

  事实上,我们并不用考虑经过的每一条边的方向!这并不是我们决策的关键,只要最后回到起点即可,如下图所示。

  

  

建图

  怎么用最大流来限制这两个条件呢?

  先上效果图:

  

  对于度数为2,考虑用一条容量为2的边限制。可以从源点向左边的每个点连接一条容量为2的边。

  对于连到一个点的两条边的颜色不可以相同的限制,对于每一个点$u$新建$k$个点$u_1,u_2,...u_k$,并向它们连一条容量为1的边。这限制了每个点的每个颜色的出边至多只能有一条!

  对于右边的点,我们镜像过去就好。

  题目所连的边,我们按指定点的对应颜色,从左向右连接一条容量为1的边。

  愉快地跑一次Dinic最大流。

  由于题目保证一定有解,那么对于每一个连通块,块内所有点对应的2边一定是满流的。

  也意味着,中间带颜色的边(即输入边),满流的就是答案经过的。

构造

  现在我们只看答案经过的边,对于每个连通块直接模拟一笔画就好啦(随缘乱画),输出答案即可。


  我的编号规则:

    左边$n$个点:$[1,n]$

    右边$n$个点:$(n,2n]$

    每个点对应的$k$个颜色点:$(2n,2n+2nk]$。

    源点:$2n+2nk+1$  汇点:$2n+2nk+2$

  (PS:这题的代码本来可以1A的然而输出的时候全部输出成最后一天了...天数和长度都对..看起来并没有什么不对...)

 #include <cstdio>
#include <queue>
#include <cstring>
#include <vector>
using namespace std;
const int N=,INF=;
int n,m,k,tot,h[],S,T,ch[N*][],chcnt,rec[][];
int vis[],dis[],has[N*];
vector<int> lis[N*],ans[N*];
struct Edge{int v,f,next;}g[];
queue<int> q;
inline int addEdge(int u,int v,int f){
g[++tot].v=v; g[tot].f=f; g[tot].next=h[u]; h[u]=tot;
g[++tot].v=u; g[tot].f=; g[tot].next=h[v]; h[v]=tot;
return tot-;
}
bool bfs(){
memset(dis,-,sizeof dis);
while(!q.empty()) q.pop();
dis[S]=; q.push(S);
int u,v;
while(!q.empty()){
u=q.front(); q.pop();
for(int i=h[u];i;i=g[i].next)
if(g[i].f&&dis[(v=g[i].v)]==-){
dis[v]=dis[u]+;
q.push(v);
}
}
return dis[T]!=-;
}
int dinic(int u,int delta){
if(u==T) return delta;
int v,get,ret=;
for(int i=h[u];i&&delta;i=g[i].next)
if(g[i].f&&dis[(v=g[i].v)]==dis[u]+){
get=dinic(v,min(g[i].f,delta));
g[i].f-=get;
g[i^].f+=get;
delta-=get;
ret+=get;
}
if(!delta) dis[u]=-;
return ret;
}
int main(){
scanf("%d%d%d",&n,&m,&k);
tot=;
S=n*+n**k+; T=S+;
chcnt=n*;
for(int i=;i<=n*;i++){
if(i<=n) has[i]=addEdge(S,i,);
else has[i]=addEdge(i,T,);
for(int j=;j<=k;j++){
ch[i][j]=++chcnt;
if(i<=n) addEdge(i,ch[i][j],);
else addEdge(ch[i][j],i,);
}
}
for(int i=,x,y,z;i<=m;i++){
scanf("%d%d%d",&x,&y,&z);
rec[i][]=addEdge(ch[x][z],ch[y+n][z],);
rec[i][]=x; rec[i][]=y+n;
}
while(bfs())
dinic(S,INF);
for(int i=;i<=m;i++){
int u=rec[i][],v=rec[i][],id=rec[i][];
if(!g[id].f&&!g[has[u]].f&&!g[has[v]].f){
lis[u].push_back(v);
lis[v].push_back(u);
}
}
int day=;
for(int i=;i<=n;i++)
if(!vis[i]){
vis[i]=;
ans[++day].push_back(i);
for(int u=i,go=-;go!=i;u=go){
if(!vis[lis[u][]]) go=lis[u][];
else if(!vis[lis[u][]]) go=lis[u][];
else break;
vis[go]=;
ans[day].push_back(go);
}
ans[day].push_back(i);
}
printf("%d\n",day);
for(int i=;i<=day;i++){
int siz=ans[i].size();
printf("%d ",siz);
for(int j=;j<siz;j++)
if(ans[i][j]<=n) printf("L%d ",ans[i][j]);
else printf("R%d ",ans[i][j]-n);
puts("");
}
return ;
}

奇妙代码

【2016北京集训测试赛(十六)】 River (最大流)的更多相关文章

  1. 2016北京集训测试赛(六)Problem B: 矩阵

    Solution 最小割. 参考BZOJ 3144切糕 在那道题的基础上将建图方法稍作变形: 我们对格子进行黑白染色, 对于两个格子之和\(\le k\)的限制, 就可以确定其中一个是白色格子, 一个 ...

  2. 2016北京集训测试赛(六)Problem A: 冒泡排序

    Solution 观察冒泡排序的过程. 我们注意到, 每一轮的排序都会使得每个数后面比它小的数的个数减\(1\). 我们用\(f(n, m)\)表示对\(1\)到\(n\)的一个排列进行冒泡排序, 满 ...

  3. 2016北京集训测试赛(十六)Problem B: river

    Solution 这题实际上并不是构造题, 而是一道网络流. 我们考虑题目要求的一条路径应该是什么样子的: 它是一个环, 并且满足每个点有且仅有一条出边, 一条入边, 同时这两条边的权值还必须不一样. ...

  4. 2016北京集训测试赛(十六)Problem C: ball

    Solution 这是一道好题. 考虑球体的体积是怎么计算的: 我们令\(f_k(r)\)表示\(x\)维单位球的体积, 则 \[ f_k(1) = \int_{-1}^1 f_{k - 1}(\sq ...

  5. 2016北京集训测试赛(十六)Problem A: 任务安排

    Solution 这道题告诉我们, 不能看着数据范围来推测正解的时间复杂度. 事实证明, 只要常数足够小, \(5 \times 10^6\)也是可以跑\(O(n \log n)\)算法的!!! 这道 ...

  6. 【2016北京集训测试赛(十)】 Azelso (期望DP)

    Time Limit: 1000 ms   Memory Limit: 256 MB Description 题解 状态表示: 这题的状态表示有点难想...... 设$f_i$表示第$i$个事件经过之 ...

  7. 【2016北京集训测试赛】river

    HINT 注意是全程不能经过两个相同的景点,并且一天的开始和结束不能用同样的交通方式. [吐槽] 嗯..看到这题的想法的话..先想到了每个点的度为2,然后就有点不知所措了 隐隐约约想到了网络流,但并没 ...

  8. 2016北京集训测试赛(十四)Problem B: 股神小D

    Solution 正解是一个\(\log\)的link-cut tree. 将一条边拆成两个事件, 按照事件排序, link-cut tree维护联通块大小即可. link-cut tree维护子树大 ...

  9. 2016北京集训测试赛(十四)Problem A: 股神小L

    Solution 考虑怎么卖最赚钱: 肯定是只卖不买啊(笑) 虽然说上面的想法很扯淡, 但它确实能给我们提供一种思路, 我们能不买就不买; 要买的时候就买最便宜的. 我们用一个优先队列来维护股票的价格 ...

随机推荐

  1. 转-Windows路由表配置:双网卡路由分流

    原文链接:http://www.cnblogs.com/lightnear/archive/2013/02/03/2890835.html 一.windows 路由表解释 route print -4 ...

  2. 02_HTML5+CSS详解第四天

    依旧是CSS部分贴个CSS主要知识点总结的链接:http://blog.csdn.net/html5_/article/details/26098273 [自己的笔记做得好乱,以前一直以为是字丑的原因 ...

  3. 常用Nagios配置命令

    cd /usr/local/nagios/etc vim nagios.cfg /usr/local/nagios/bin/nagios -v /usr/local/nagios/etc/nagios ...

  4. 02-创建 TLS CA证书及密钥

    创建 TLS CA证书及密钥 kubernetes 系统的各组件需要使用 TLS 证书对通信进行加密,本文档使用 CloudFlare 的 PKI 工具集 cfssl 来生成 Certificate ...

  5. [SF] Symfony 组件 BrowserKit 原理

    直接看下面的注释中针对每一个文件的作用说明. <?php /** * BrowserKit - Make internal requests to your application. * * I ...

  6. [DeeplearningAI笔记]神经网络与深度学习人工智能行业大师访谈

    觉得有用的话,欢迎一起讨论相互学习~Follow Me 吴恩达采访Geoffrey Hinton NG:前几十年,你就已经发明了这么多神经网络和深度学习相关的概念,我其实很好奇,在这么多你发明的东西中 ...

  7. linux基本语法和常用运维命令

    linux上的操作一般是命令行操作,看起来很高大上,让人畏而远之. Help!Help! 忽然间闯入的linux黑黑的世界,怎么办,不要慌.赶紧敲出一个help命令,然后回车,黑色的窗口就会展示一些常 ...

  8. 论事件驱动与异步IO

    通常我们写服务器模型,有以下几种模型: 每收到一个请求,创建一个新的进程,来处理该请求 每收到一个请求,创建一个新的线程,来处理该请求 每收到一个请求,放入到一个事件中,让主程序通过非阻塞I/0方式来 ...

  9. xBIM 使用Linq 来优化查询

    目录 xBIM 应用与学习 (一) xBIM 应用与学习 (二) xBIM 基本的模型操作 xBIM 日志操作 XBIM 3D 墙壁案例 xBIM 格式之间转换 xBIM 使用Linq 来优化查询 x ...

  10. RAID知识总结[转]

    原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://815632410.blog.51cto.com/1544685/1394306 ...