POJ - 1815 Friendship (最小点割集)
题目分析
题意:有n个人,编号记为1~n,n个人之间可能有人可以互相联系,如果A能和B联系,那么至少满足这两种情况之一:(1)A知道B的电话(2)A可以和C联系,并且C可以和B联系;
因为某些人可能会丢失他的手机,导致他失去所有人的号码以及其他人手机中他的号码,也就是说这个人无法和任何人联系了;
此时给出两个人s,t,问至少有多少人失去他们的手机,可以使得这两个人s,t无法联系。
答案输出最少需要的人数以及失去手机的人的编号,如果存在多组解,输出字典序小的那一组。
思路:平时写的最小割问题是求边割集,这个题题目求的是最小点割集,对于这类题目我们采用如下建边方法:
1)将每个人代表的结点拆成两个结点,记编号1~n为入点,n+1~2*n为出点,由入点向出点建一条容量为1的边
2)对于可以联系的两人 a,b,由a的出点向b的入点建一条容量为inf的边,并由b的出点向a的入点建一条容量为inf的边
3)由于源点就是某个人,那么我们将这个人的出点当作源点
建好边之后,我们跑一遍最大流(最小割)就可以得到最小点割集
个人认为这个题主要麻烦在输出割点,我的方法是不断地的删点,如果删去这一点后得到的最大流大于删这点之前的最大流,那么这个点就是割点,为保证字典序最小,因而从1开始枚举割点
代码区
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#include<string>
#include<fstream>
#include<vector>
#include<stack>
#include <map>
#include <iomanip> #define bug cout << "**********" << endl
#define show(x, y) cout<<"["<<x<<","<<y<<"] "
#define LOCAL = 1;
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const ll mod = ;
const int Max = 1e5 + ;
const int Max2 = 1e3 + ; struct Edge
{
int to, flow, next;
} edge[Max << ]; int n, s, t;
int head[Max2], tot;
int dis[Max2];
bool vis[][], cancel[];
int id[Max2], cnt; void init()
{
memset(head, -, sizeof(head));tot = ;
} void add(int u, int v, int flow)
{
edge[tot].to = v;
edge[tot].flow = flow;
edge[tot].next = head[u];
head[u] = tot++;
} void build()
{
init();
for (int i = ; i <= n; i++)
{
if (!cancel[i])
{
add(i, i + n, );
add(i + n, i, );
}
}
for (int i = ; i <= n; i++)
{
for (int j = ; j <= n; j++)
{
if(vis[i][j])
{
add(i + n, j, inf);
add(j, i + n, );
}
}
}
} bool bfs()
{
memset(dis, -, sizeof(dis));
queue<int> q;
q.push(s);
dis[s] = ;
while (!q.empty())
{
int u = q.front();
q.pop();
for (int i = head[u]; i != -; i = edge[i].next)
{
int v = edge[i].to;
if (edge[i].flow > && dis[v] == -)
{
dis[v] = dis[u] + ;
if (v == t)
return true;
q.push(v);
}
}
}
return false;
} int dfs(int u, int flow_in)
{
if (u == t)
return flow_in;
int flow_out = ;
for (int i = head[u]; i != -; i = edge[i].next)
{
int v = edge[i].to;
if (edge[i].flow > && dis[v] == dis[u] + )
{
int flow = dfs(v, min(flow_in, edge[i].flow));
if (flow == )
continue;
flow_in -= flow;
flow_out += flow;
edge[i].flow -= flow;
edge[i ^ ].flow += flow;
if (flow_in == )
break;
}
}
return flow_out;
} int Dinic()
{
int sum = ;
while (bfs())
{
sum += dfs(s, inf);
}
return sum;
} int main()
{
#ifdef LOCAL
//freopen("input.txt", "r", stdin);
//freopen("output.txt", "w", stdout);
#endif
while (scanf("%d%d%d", &n, &s, &t) != EOF)
{
memset(cancel, , sizeof(cancel));
memset(vis, , sizeof(vis));
cnt = ;
for (int i = ; i <= n; i++)
{
for (int j = ,x; j <= n; j++)
{
scanf("%d", &x);
vis[i][j] = x;
}
}
if(vis[s][t]) //s,t可以直接联系,那就不存在最小割了
{
printf("NO ANSWER!\n");
continue;
}
s += n;
build();
int min_cost = Dinic(); printf("%d\n", min_cost);
if (min_cost == )
continue;
int last = min_cost;
for (int i = ; i <= n; i++)
{
if (i + n == s || i == t)
continue;
cancel[i] = true;
build();
int temp = Dinic();
if (temp < last) //相比于不删除i点,删除i点之后最大流减少,则此点为割点
{
id[++cnt] = i;
last--;
if (cnt == min_cost)
break;
}
else
{
cancel[i] = false;
}
}
for (int i = ; i < cnt; i++)
printf("%d ", id[i]);
printf("%d\n", id[cnt]);
}
return ;
}
POJ - 1815 Friendship (最小点割集)的更多相关文章
- POJ 1815 Friendship(最小割)
http://poj.org/problem? id=1815 Friendship Time Limit: 2000MS Memory Limit: 20000K Total Submissio ...
- poj 1815 Friendship (最小割+拆点+枚举)
题意: 就在一个给定的无向图中至少应该去掉几个顶点才干使得s和t不联通. 算法: 假设s和t直接相连输出no answer. 把每一个点拆成两个点v和v'',这两个点之间连一条权值为1的边(残余容量) ...
- POJ 1815 - Friendship - [拆点最大流求最小点割集][暴力枚举求升序割点] - [Dinic算法模板 - 邻接矩阵型]
妖怪题目,做到现在:2017/8/19 - 1:41…… 不过想想还是值得的,至少邻接矩阵型的Dinic算法模板get√ 题目链接:http://poj.org/problem?id=1815 Tim ...
- POJ 1815 Friendship ★(字典序最小点割集)
[题意]给出一个无向图,和图中的两个点s,t.求至少去掉几个点后才能使得s和t不连通,输出这样的点集并使其字典序最大. 不错的题,有助于更好的理解最小割和求解最小割的方法~ [思路] 问题模型很简单, ...
- POJ 1815 Friendship(字典序最小的最小割)
Friendship Time Limit: 2000MS Memory Limit: 20000K Total Submissions: 10744 Accepted: 2984 Descr ...
- poj 1815 Friendship 字典序最小+最小割
题目链接:http://poj.org/problem?id=1815 In modern society, each person has his own friends. Since all th ...
- POJ 1815 Friendship (Dinic 最小割)
Friendship Time Limit: 2000MS Memory Limit: 20000K Total Submissions: 8025 Accepted: 2224 Descri ...
- POJ 1815 Friendship(最小割+字典序输出割点)
http://poj.org/problem?id=1815 题意: 在现代社会,每个人都有自己的朋友.由于每个人都很忙,他们只通过电话联系.你可以假定A可以和B保持联系,当且仅当:①A知道B的电话号 ...
- poj 1815 Friendship【最小割】
网络流的题总是出各种奇怪的错啊--没写过邻接表版的dinic,然后bfs扫到t点不直接return 1就会TTTTTLE-- 题目中的操作是"去掉人",很容易想到拆点,套路一般是( ...
随机推荐
- 11-ajax
Ajax 1.什么是ajax Asynchronous JavaScript and XML(异步JavaScript和XML) 节省用户操作,时间,提高用户体验,减少数据请求 传输获取数据 特点 ...
- git commit -m "XX"报错 pre -commit hook failed (add --no-verify to bypass)问题
在同步本地文件到线上仓库的时候 报错 pre -commit hook failed (add --no-verify to bypass) 当你在终端输入git commit -m "xx ...
- hadoop-httpfs
Hadoop-httpfs: client向httpfs提交文件操作,由httpfs和集群交互: 优势:client不必访问集群 WebHDFS API: https://archive.cloude ...
- [洛谷P3941]:入阵曲(前缀和+桶)
题目传送门 题目背景 丹青千秋酿,一醉解愁肠.无悔少年枉,只愿壮志狂. 题目描述 小$F$很喜欢数学,但是到了高中以后数学总是考不好.有一天,他在数学课上发起了呆:他想起了过去的一年.一年前,当他初识 ...
- PHP依赖管理工具Composer入门
作者: JeremyWei | 可以转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明 网址: http://weizhifeng.net/manage-php-dependency-wi ...
- JavaScript数字计算精度丢失的问题和解决方案
一.JS数字精度丢失的一些典型问题 1. 两个简单的浮点数相加:0.1 + 0.2 != 0.3 // true,下图是firebug的控制台截图: 看看java的计算结果:是不是让你很不能接受 再来 ...
- Ubuntu下qt5使用vlc
一:Ubuntu下在线安装qt5,同时安装了qt creator 二:打开终端执行sudo apt-get install libvlc5 libvlc-dev libvlccore-dev 安装 ...
- HearthBuddy的狂野和休闲模式来回切换
表现1 配置是标准,休闲模式 然后一直重复提示 select desire deck select causal mode 表现2 配置是狂野,休闲模式 然后一直提示 切换到狂野 切换到标准 把模式切 ...
- vue-cli 3x 的使用
当我们使用 npm 下载过文件之后,里面就会有缓存 我们要使用 npm cache clean --force 来清除缓存 创建项目:vue create 文件名 然后:cd 文件名 启动程序:npm ...
- Hive数据提取
Hive是基于Hadoop的ETL工具和数据仓库. 结构化数据 结构化数据就像RDBMS hive> create table structured_table(id int, name str ...