XJOJ - 选信封(离散化+增广路)
题目链接:点击查看
题目大意:Dumbulidone和Euphemia玩一个挑卡片游戏.
Dumbulidone会给出N对信封,每个信封里有两张不同颜色的卡片,她会让Euphemia从中挑选任意个信封,但是一对信封中最多只能挑选一个,(信封是透明的,可以看到里面卡片颜色)。等Euphemia挑好后,Dumbulidone会尝试从Euphemia挑出的信封中再选出若干个(不可以不取),把其中的卡片取出,若存在一种方案使得取出的卡片中,每种颜色的卡片都有偶数张,那么Dumbulidone就赢了。Euphemia想知道在自己赢的前提下,她最多能选出多少信封。
输入格式:
第一行一个整数N。
接下来N行,每行4个整数,描述一对信封中卡片颜色,前两个是一个信封中的,后两个是一个信封中的。
输出格式:
一个整数,表示答案。
样例输入:
样例输入一 4 0 1 0 5 5 1 0 5 1 2 0 1 1 5 2 0 样例输入二 6 1 4 1 4 2 4 2 4 0 3 0 3 0 4 0 4 4 3 4 3 1 3 1 3
样例输出:
样例输出一 3 样例输出二 4
数据范围:
对于30%的数据满足N<=10
对于100%的数据满足N<=300,所有数<=10^7.
时间限制:
1S
空间限制:
256M
题目分析:感觉挺好的一道题目,断断续续想了三天差不多想明白了该怎么做,首先题目的意思比较抽象,我们需要转换一下,可以将颜色视为点,信封视为边,问题就转换为了,最多可以选择多少条边,使得组成的图中不存在环,因为前面的选择会影响到全局的结果,所以不能用dp转移状态,在图论中可以寻找增广路来使得答案最优,每次不断尝试寻找增广路更新答案就好了,因为数据比较小,我们可以直接枚举每条边,尝试加入到图中,如果可以直接加入的话,也就是加入某条边后图中仍然无环,那么这条边就可以直接加入,相反如果加入后会出现环,那么需要寻找增广路,这里寻找增广路的方法和匈牙利算法的很像,也是类似于二分图,这里二分图的一个部分代表着已经用过的边,另一部分代表着没有用过的边,如果加入某条边后会让图中出现环,那么显然这条边和环上的其他边是不能同时存在于一个部分的,我们可以建边,这里的建边是对于信封建边,也就是代表着这两个信封不能同时选择,对信封建好边后,尝试能否增广就好了,可以增广的条件是找到一条信封连成的路,使得第一个信封和最后一个信封都属于二分图中没有用过的边
最后就是因为颜色比较多,但我们实际上用不到其绝对大小,所以离散化一下得到其相对大小,方便后续操作
代码:
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
using namespace std;typedef long long LL;typedef unsigned long long ull;const int inf=0x3f3f3f3f;const int N=610;vector<int>v; int f[N],n;struct Edge
{int u,v,vis;Edge(){vis=0;}
}Edge[N];void discreate()//离散化
{sort(v.begin(),v.end());v.erase(unique(v.begin(),v.end()),v.end());for(int i=0;i<2*n;i++){Edge[i].u=lower_bound(v.begin(),v.end(),Edge[i].u)-v.begin();Edge[i].v=lower_bound(v.begin(),v.end(),Edge[i].v)-v.begin();}
}int find(int x)
{return f[x]==x?x:f[x]=find(f[x]);
}bool merge(int x,int y)
{int xx=find(x);int yy=find(y);if(xx!=yy){f[xx]=yy;return true;}return false;
}struct Node
{int to,id;Node(int to,int id):to(to),id(id){}
};vector<Node>point[N<<1];//颜色连边 vector<int>edge[N];//信封连边 void init_point()
{for(int i=0;i<v.size();i++)f[i]=i;for(int i=0;i<v.size();i++)point[i].clear();
}void build_point(int now)//建立点之间的联系
{ init_point();for(int i=0;i<now;i++)if(Edge[i].vis){int u=Edge[i].u;int v=Edge[i].v;point[u].push_back(Node(v,i));point[v].push_back(Node(u,i));merge(u,v);}
}bool ok[N];//标记哪条边可以作为增广路的终边 int vis[N];bool dfs(int u,int fa,int id)//找环
{if(u==fa)//有环 return true;vis[u]=id;for(int i=0;i<point[u].size();i++){int v=point[u][i].to;if(vis[v]==id)continue;if(dfs(v,fa,id))//将环上的所有信封与id信封连边 {edge[id].push_back(point[u][i].id);edge[point[u][i].id].push_back(id);return true;}}return false;
}void init_edge(int now)
{for(int i=0;i<=(now^1);i++)edge[i].clear();memset(ok,false,sizeof(ok));memset(vis,-1,sizeof(vis));
}void build_edge(int now)//建立信封之间的联系
{init_edge(now);for(int i=0;i<=now;i++)edge[i].push_back(i^1);for(int i=0;i<=now;i++){if(!Edge[i].vis)//如果这条边没被用过{if(dfs(Edge[i].u,Edge[i].v,i))//加入后有环ok[i]=false;else//无环 ok[i]=true; }}
}bool dfs(int u)
{vis[u]=true;for(int i=0;i<edge[u].size();i++){int v=edge[u][i];if(vis[v])continue;if((Edge[u].vis^Edge[v].vis)==1){if(ok[v]||dfs(v)){Edge[v].vis^=1;return true;}}}return false;
}int main()
{
#ifndef ONLINE_JUDGE
// freopen("input.txt","r",stdin);
// freopen("output.txt","w",stdout);
#endif
// ios::sync_with_stdio(false);scanf("%d",&n);for(int i=0;i<2*n;i++){scanf("%d%d",&Edge[i].u,&Edge[i].v);v.push_back(Edge[i].u);v.push_back(Edge[i].v);}discreate();int ans=0;for(int i=0;i<2*n;i++)//遍历每个信封 {build_point(i);//对于颜色建边if(merge(Edge[i].u,Edge[i].v))//加入后无环,则直接加入 {Edge[i].vis=true;ans++;continue;}build_edge(i);//对于信封建边memset(vis,false,sizeof(vis));if(dfs(i))//可以找到增广路,则说明可以加入这条边 {Edge[i].vis=true;ans++;}}printf("%d\n",ans);return 0;
}
XJOJ - 选信封(离散化+增广路)相关推荐
- 网络流—Edmonds-Karp 最短增广路算法(最大流)
网络流----Edmonds-Karp 最短增广路算法 ■求最大流的过程,就是不断找到一条源到汇的路径,然后构建残余网络,再在残余网络上寻找新的路径,使总流量增加,然后形成新的残余网络,再寻找新路径- ...
- 【网络流】解题报告:luogu P2740 [USACO4.2]草地排水Drainage Ditches(Edmonds-Karp增广路,最大流模板)
题目链接:草地排水 若一条从源点到汇点的路径上各条边的剩余容量都大于0,则称这条路径为一条增广路. Edmonds-Karp增广路的策略就是不断用bfs寻找增广路,直至网络中不在存在增广路为止. 在每 ...
- hdu 1281(二分图匹配+增广路)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1281 解题思路: 把棋盘的行x看成二分图左边的点,列y看成二分图右边的点,那么就把可以放车的位置看成是 ...
- 网络流 增广路 回退
增广路: 有流量标记: 流量变化: 转载于:https://www.cnblogs.com/cmyg/p/9568904.html
- 网络最大流中一般增广路算法(标号法)
网络最大流主要有两大类求解方法:增广路算法和预流推进算法 一般增广路算法:主要分为初始流为零流和初始流为非零流的情况!后者在标号的时候注意一条边是正向连接还是反向连接:若是反向的连接,那么在调整的时候 ...
- 最短增广路Isap算法 网络流
最短增广路 请先理解 bfs的求增广路的算法,再来学习Isap算法 最短增广路Isap算法 图片来源 <趣学算法>人民邮电出版社 陈小玉 /* 最短可增广路:重贴标签算法Isap 算法设计 ...
- 增广路算法 (最大流问题)
Edmonds-Karp算法: 计算机科学中, Edmonds–Karp算法通过实现Ford–Fulkerson算法来计算网络中的最大流,其时间复杂度为O(V E2). 该算法由Yefim (Chai ...
- SAP和ISAP(网路最大流的两个增广路算法)
ISAP是对SAP进行优化后的算法,ISAP时间复杂度为O(V^2E),SAP的时间复杂度为O(VE^2) SAP #include <iostream> #include <alg ...
- 二分图前期基础之增广路
二分图前期基础之增广路 刚开始学习的时候,总是受困于增广路径,不明白增广路径是如何应用以及其具体的含义是什么,感谢博客https://www.cnblogs.com/logosG/p/logos.ht ...
最新文章
- spring-amqp整合rabbitmq消费者配置和代码
- 第十六届智能车竞赛英飞凌技术培训日程安排
- Emmet:HTML/CSS代码快速编写规范(转发)
- Nature报道新冠病毒新研究:传猫易,传狗难,猫狗能否传人不明确
- 企业网络推广专员浅析如何通过企业网络推广的方式提升网站权重?
- 记录TCP协议使用Socket连接,客户端请求服务器read()阻塞问题
- 路由器功能 后台管理 各功能 介绍
- 挖掘频繁模式、关联和相关性:基本概念和方法
- Vector Math for 3D Computer Graphics
- 计算机网络应用基础_学习笔记之《计算机网络》概述
- Java知多少(2)虚拟机(JVM)以及跨平台原理
- Mysql报错(必解决):The user specified as a definer (‘mysql.infoschema‘@‘localhost‘) does not exist
- CAD快捷键命令大全
- 一行Python代码让图形秒变「手绘风」
- 如何在微信开发者工具中插入图片
- 卡片跳转快应用指定页面,如何点返回直接退出快应用回到卡片
- IDEA更换背景图片
- Intellij idea 2020设置经典样式(背景为黑色Darcula)
- 【FPGA知识点】八段共阳极数码管编码表
- 关于Bootstrap的一些使用