hdu 5899 oasis in desert(acm/icpc 沈阳赛区网络赛,Floyd+二分图判定+最大匹配,好难啊)
来源:互联网 发布:全国行政区街道数据库 编辑:程序博客网 时间:2024/05/22 11:33
传送门: http://acm.hdu.edu.cn/showproblem.php?pid=5899
题目大意:
沙漠中有N个绿洲,由M条路相连,每条路的长度为L。
定义两个集合:
(1)最大危险集:对于集合中任意两点,其最小距离大于k,满足此条件的集合有多个,取最大的那个。
(2)最小安全集:对于图中任意两点,只要他俩的距离≤k,那么最小安全集中至少包含这两个点中的一个。满足条件的集合有多个,取最小的那个。
问这个图中存不存在一个点集,它既是最大危险集,又是最小安全集。
如果存在,输出字典序最小的那个集合,如果不存在,输出Impossible。
题目分析:
其实拿到这个题,想到了跟二分图匹配有关系,但一开始是把原图的点拆成两个,怎么想也对不上。看了这位大神http://blog.csdn.net/wmdcstdio/article/details/52576840的题解就明白了。
这道题应该这样构图:
构建图
接下来是见证奇迹的时刻~~
我们假设一个点v1属于答案集,那么:
1. v1点相邻的点一定不属于答案集;(因为最大危险集定义)
2. 和1中相邻的点一定属于答案集;(因为最小安全集定义)
3. 和2中相邻的点一定不属于答案集;
….
因此得出结论:
1.图
2.“最大危险集”即为图
3.“最小安全集”即为图
我们都知道,最大独立集+最小支配集=图的总点数,所以说,答案集存在只需最大匹配=n/2即可。
这里面还有一个问题,我也在这里wa了六七发。那就是输入的原图有可能不连通,这种情况要输出impossible。上述博主在这里似乎有点问题,因为如果不连通,就算每个子图都存在这种答案集,如果取了并集也会存在两个点他们是连不通的,而“最小距离大于k”的前提是存在最小距离,他俩都连不通,就没有意义。所以还要加一条判断就是,图G是连通的!!!
求最小距离用了Floyd算法,判定二分就是裸的dfs,然后求最大匹配用了一个匈牙利算法。
#include <bits/stdc++.h>using namespace std;typedef long long ll;#define INF 0x3f3f3f3fint t,n,m,k,a,b,l;int p[510];//记录每个点的颜色,0没染,1黑色,2白色int dis[510][510];//因为要算距离,所以用邻接矩阵存图vector<int> g[510];int f[510],vis[510];int cnt;void floyd() { for(int k=1;k<=n;k++) for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);}void initGraph() { //构造图g,当i-j边距离小于等于k的时候,给i-j加一条边 for(int i=1;i<=n;i++) { for(int j=i+1;j<=n;j++) { if(dis[i][j]<=k) { g[i].push_back(j); g[j].push_back(i); } } }}bool dfs(int u,int col) { //给i点染col色 //cout<<u<<","<<col<<endl; p[u]=col; for(int i=0;i<g[u].size();i++) { int v=g[u][i]; if(p[v]==col)//如果相邻的两个点颜色一样,那就是非法的 return false; else if(p[v]==0) { if(col==1) { if(!dfs(v,2)) return false; } else { if(!dfs(v,1)) return false; } } } return true;}bool paint() { //v1.clear();v2.clear(); for(int i=1;i<=n;i++) { if(p[i]==0) { p[i]=1; if(!dfs(i,1)) return false; } } return true;}bool dfs2(int i) { vis[i]=1; for(int j=0;j<g[i].size();j++) { int u=g[i][j]; if(f[u] == -1 || (!vis[f[u]] && dfs2(f[u]))) { f[u]=i; f[i]=u; return 1; } } return 0;}bool match() { memset(f,-1,sizeof(f)); for(int i=1;i<=n;i++) { if(f[i]==-1) { memset(vis,0,sizeof(vis)); cnt+=dfs2(i); } } return cnt*2==n;}void solve() { int con=1; for(int i=1;i<=n;i++) if(dis[1][i]<INF) con++; if(!paint() || con<n || !match()) printf("Impossible\n"); else { vector<int> ans; for(int i=1;i<=n;i++) if(p[i]==1) ans.push_back(i); printf("%d\n", ans.size()); for(int i=0;i<ans.size()-1;i++) printf("%d ", ans[i]); printf("%d\n", ans.back()); }}int main() { scanf("%d",&t); while(t--) { scanf("%d %d %d",&n,&m,&k); memset(dis,0x3f,sizeof(dis)); for(int i=1;i<=n;i++) dis[i][i]=0; memset(p,0,sizeof(p)); memset(g,0,sizeof(g)); cnt=0; while(m--) { scanf("%d %d %d",&a,&b,&l); dis[a][b]=l;dis[b][a]=l; } if(n==0) { //特判0个点 printf("0\n"); continue; } floyd(); initGraph(); solve(); }}
- hdu 5899 oasis in desert(acm/icpc 沈阳赛区网络赛,Floyd+二分图判定+最大匹配,好难啊)
- 【HDU】5899 oasis in desert 【二分匹配】
- hdu 5899 oasis in desert
- 2017 ACM-ICPC 亚洲区(沈阳赛区)网络赛
- hdu 5898 odd even number(acm/icpc沈阳赛区网络赛,数位DP)
- hdu 5898 odd-even number 2016ACM/ICPC沈阳赛区网络赛1007
- hdu 5893 List wants to travel 2016ACM/ICPC沈阳赛区网络赛1002
- hdu 5892 List wants to travel 2016ACM/ICPC沈阳赛区网络赛1001
- hdu 2444 二分图判定+最大匹配
- HDU 2444 (二分图判定+最大匹配)
- HDU - 2444 二分图判定 + 最大匹配
- 2015 ACM/ICPC 沈阳赛区网络赛 1010.Jesus Is Here (HDOJ5459)
- HDU6195 | 2017 ACM-ICPC 亚洲区(沈阳赛区)网络赛-B cable cable cable
- HDU6201 | 2017 ACM-ICPC 亚洲区(沈阳赛区)网络赛-H transaction transaction transaction
- HDU6201 | 2017 ACM-ICPC 亚洲区(沈阳赛区)网络赛-H transaction transaction transaction
- HDU6201 | 2017 ACM-ICPC 亚洲区(沈阳赛区)网络赛-H transaction transaction transaction
- HDU 5510 2015ACM-ICPC沈阳赛区现场赛B题
- HDU 5512 2015ACM-ICPC沈阳赛区现场赛D题
- java.util.ListIterator学习笔记
- buntun 安装sublime3 text插件
- git免密码 pull push
- PHP中面向对象关于验证码
- js indexof用法
- hdu 5899 oasis in desert(acm/icpc 沈阳赛区网络赛,Floyd+二分图判定+最大匹配,好难啊)
- 深入理解Java的接口和抽象类
- Azure Queue Storage 基本用法 -- Azure Storage 之 Queue
- jenkins远程部署play framework项目时遇到的问题及解决办法
- qml学习------Button属性
- 注意:靠谱公司一定没有这些,别跳到坑里了
- JDBC查询
- CSS基础之1:CSS概念,书写位置,语法,CSS各种选择器
- UIAlertController的使用及其自定义