题目链接:点击查看

题目大意: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 - 选信封(离散化+增广路)相关推荐

  1. 网络流—Edmonds-Karp 最短增广路算法(最大流)

    网络流----Edmonds-Karp 最短增广路算法 ■求最大流的过程,就是不断找到一条源到汇的路径,然后构建残余网络,再在残余网络上寻找新的路径,使总流量增加,然后形成新的残余网络,再寻找新路径- ...

  2. 【网络流】解题报告:luogu P2740 [USACO4.2]草地排水Drainage Ditches(Edmonds-Karp增广路,最大流模板)

    题目链接:草地排水 若一条从源点到汇点的路径上各条边的剩余容量都大于0,则称这条路径为一条增广路. Edmonds-Karp增广路的策略就是不断用bfs寻找增广路,直至网络中不在存在增广路为止. 在每 ...

  3. hdu 1281(二分图匹配+增广路)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1281 解题思路: 把棋盘的行x看成二分图左边的点,列y看成二分图右边的点,那么就把可以放车的位置看成是 ...

  4. 网络流 增广路 回退

    增广路: 有流量标记: 流量变化: 转载于:https://www.cnblogs.com/cmyg/p/9568904.html

  5. 网络最大流中一般增广路算法(标号法)

    网络最大流主要有两大类求解方法:增广路算法和预流推进算法 一般增广路算法:主要分为初始流为零流和初始流为非零流的情况!后者在标号的时候注意一条边是正向连接还是反向连接:若是反向的连接,那么在调整的时候 ...

  6. 最短增广路Isap算法 网络流

    最短增广路 请先理解 bfs的求增广路的算法,再来学习Isap算法 最短增广路Isap算法 图片来源 <趣学算法>人民邮电出版社 陈小玉 /* 最短可增广路:重贴标签算法Isap 算法设计 ...

  7. 增广路算法 (最大流问题)

    Edmonds-Karp算法: 计算机科学中, Edmonds–Karp算法通过实现Ford–Fulkerson算法来计算网络中的最大流,其时间复杂度为O(V E2). 该算法由Yefim (Chai ...

  8. SAP和ISAP(网路最大流的两个增广路算法)

    ISAP是对SAP进行优化后的算法,ISAP时间复杂度为O(V^2E),SAP的时间复杂度为O(VE^2) SAP #include <iostream> #include <alg ...

  9. 二分图前期基础之增广路

    二分图前期基础之增广路 刚开始学习的时候,总是受困于增广路径,不明白增广路径是如何应用以及其具体的含义是什么,感谢博客https://www.cnblogs.com/logosG/p/logos.ht ...

最新文章

  1. spring-amqp整合rabbitmq消费者配置和代码
  2. 第十六届智能车竞赛英飞凌技术培训日程安排
  3. Emmet:HTML/CSS代码快速编写规范(转发)
  4. Nature报道新冠病毒新研究:传猫易,传狗难,猫狗能否传人不明确
  5. 企业网络推广专员浅析如何通过企业网络推广的方式提升网站权重?
  6. 记录TCP协议使用Socket连接,客户端请求服务器read()阻塞问题
  7. 路由器功能 后台管理 各功能 介绍
  8. 挖掘频繁模式、关联和相关性:基本概念和方法
  9. Vector Math for 3D Computer Graphics
  10. 计算机网络应用基础_学习笔记之《计算机网络》概述
  11. Java知多少(2)虚拟机(JVM)以及跨平台原理
  12. Mysql报错(必解决):The user specified as a definer (‘mysql.infoschema‘@‘localhost‘) does not exist
  13. CAD快捷键命令大全
  14. 一行Python代码让图形秒变「手绘风」
  15. 如何在微信开发者工具中插入图片
  16. 卡片跳转快应用指定页面,如何点返回直接退出快应用回到卡片
  17. IDEA更换背景图片
  18. Intellij idea 2020设置经典样式(背景为黑色Darcula)
  19. 【FPGA知识点】八段共阳极数码管编码表
  20. 关于Bootstrap的一些使用

热门文章

  1. LINUX下简单制作QCOW2镜像
  2. MySQL where后面的标量子查询使用
  3. MySQL连接查询的分类
  4. 循环控制_continue语句
  5. Feign-2覆写Feign的默认配置
  6. 代理模式源码解析(jdk+spring+mybatis)
  7. 简单工厂 jdk源码解析
  8. RSA签名算法 - Java加密与安全
  9. 使用pip install出现超时警告的解决方法
  10. kafka是什么_终于知道Kafka为什么这么快了!