(点击此处查看原题)

题目分析

题意:有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 (最小点割集)的更多相关文章

  1. POJ 1815 Friendship(最小割)

    http://poj.org/problem? id=1815 Friendship Time Limit: 2000MS   Memory Limit: 20000K Total Submissio ...

  2. poj 1815 Friendship (最小割+拆点+枚举)

    题意: 就在一个给定的无向图中至少应该去掉几个顶点才干使得s和t不联通. 算法: 假设s和t直接相连输出no answer. 把每一个点拆成两个点v和v'',这两个点之间连一条权值为1的边(残余容量) ...

  3. POJ 1815 - Friendship - [拆点最大流求最小点割集][暴力枚举求升序割点] - [Dinic算法模板 - 邻接矩阵型]

    妖怪题目,做到现在:2017/8/19 - 1:41…… 不过想想还是值得的,至少邻接矩阵型的Dinic算法模板get√ 题目链接:http://poj.org/problem?id=1815 Tim ...

  4. POJ 1815 Friendship ★(字典序最小点割集)

    [题意]给出一个无向图,和图中的两个点s,t.求至少去掉几个点后才能使得s和t不连通,输出这样的点集并使其字典序最大. 不错的题,有助于更好的理解最小割和求解最小割的方法~ [思路] 问题模型很简单, ...

  5. POJ 1815 Friendship(字典序最小的最小割)

    Friendship Time Limit: 2000MS   Memory Limit: 20000K Total Submissions: 10744   Accepted: 2984 Descr ...

  6. poj 1815 Friendship 字典序最小+最小割

    题目链接:http://poj.org/problem?id=1815 In modern society, each person has his own friends. Since all th ...

  7. POJ 1815 Friendship (Dinic 最小割)

    Friendship Time Limit: 2000MS   Memory Limit: 20000K Total Submissions: 8025   Accepted: 2224 Descri ...

  8. POJ 1815 Friendship(最小割+字典序输出割点)

    http://poj.org/problem?id=1815 题意: 在现代社会,每个人都有自己的朋友.由于每个人都很忙,他们只通过电话联系.你可以假定A可以和B保持联系,当且仅当:①A知道B的电话号 ...

  9. poj 1815 Friendship【最小割】

    网络流的题总是出各种奇怪的错啊--没写过邻接表版的dinic,然后bfs扫到t点不直接return 1就会TTTTTLE-- 题目中的操作是"去掉人",很容易想到拆点,套路一般是( ...

随机推荐

  1. 【译】XMLHttpRequest和Fetch, 谁最适合AJAX?

    原文地址:https://www.sitepoint.com/xmlhttprequest-vs-the-fetch-api-whats-best-for-ajax-in-2019/ 目录 从AJAX ...

  2. Spring——多种方式实现依赖注入

    在Spring的XML配置中,只有一种声明bean的方式:使用<bean>元素并指定class属性.Spring会从这里获取必要的信息来创建bean. 但是,在XML中声明DI时,会有多种 ...

  3. Java集合框架之接口Iterator

    简述 Iterator迭代器的定义:迭代器(Iterator)模式,又叫做游标(Cursor)模式.GOF给出的定义是,提供一种方法访问一个容器(container)对象中各个元素,而又不需暴露该对象 ...

  4. [题解] [CF451E] Devu and Flowers

    题面 题解 就是一个求\(\sum_{i= 1}^{n}x _ i = m\)的不重复多重集的个数, 我们可以由容斥原理得到: \[ ans = C_{n + m - 1}^{n - 1} - \su ...

  5. C++入门经典-例8.3-子类显示调用父类构造函数

    1:当父类含有带参数的构造函数时,创建子类的时候会调用它吗?答案是通过显示方式才可以调用. 无论创建子类对象时调用的是那种子类构造函数,都会自动调用父类默认构造函数.若想使用父类带参数的构造函数,则需 ...

  6. 解决分页插件ClassNotFoundException: org.springframework.boot.bind.RelaxedPropertyResolver

    org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'com.github.p ...

  7. 阿里云maven镜像

    <mirror> <id>nexus-aliyun</id> <mirrorOf>*</mirrorOf> <name>Nexu ...

  8. 8 Linux 文件类型

    Linux 系统中的文件是没有扩展名的. 1.通过 ls -l 文件名,看第一个字符判断文件类型: -  普通文件(文本文件.二进制文件.压缩文件.电影.图片等) d  目录文件 b  设备文件(块设 ...

  9. Backen-Development record 1

    单例模式 在应用这个模式时,单例对象的类必须保证只有一个实例存在. 服务进程中的其他对象再通过这个单例对象获取这些配置信息.这种方式简化了在复杂环境下的配置管理. __new__实现 用装饰器实现单例 ...

  10. storm备忘

    [命令]storm rebalance topology-name [-w wait-time-secs] [-n new-num-workers] [-e component=parallelism ...