您的位置:首页 > 其它

poj 1815 Friendship 最小割 拆点 输出字典序

2016-03-14 21:15 375 查看
题目链接:http://poj.org/problem?id=1815

题意:A与B能通信当且仅当A知道B的电话号或者A知道C的电话号且C与B能通信。若A知道B的电话号,那么B也知道A的电话号。

然而不好的事情总会发生在某些人身上,比如他的电话本丢了,同时他又换了电话号,导致他跟所有人失去联系。

给出N个人之间的通信关系以及S和T,问最少几个人发生不好的事情可以导致S与T无法通信,并输出这些人。如果存在多组解,输出字典序最小的一组。

且假设不好的事情不会发生在S和T上,如果没有方法能使A和B失去联系,则输出"NO ANSWER!"

思路:首先需要把一个人i拆成两个点i和i'。连边(i, i', 1),那么发生不好的事情就表示这条边为割边。

然后对于i和j联通,连边(i', j, inf)和(j', i, inf)。

因为假设不好的事情不会发生在S和T上,所以把网络流的s设为S',把网络流的t设为T。

然后求一次最小割,就是答案,要注意的是如果在初始图中S和T直接联通,那么答案是"NO ANSWER!"。

要求输出字典序最小,假如一开始求出的最小割的值为x。然后可以从1到N枚举删除点,如果删除一个点之后最小割不变,那么这个点不在最小割中,把这个点恢复。

如果最小割变小了,那么更新最小割的值,输出这个点,然后不再把这个点恢复,直到输出了x个点。

//#include <bits/stdc++.h>
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <vector>
#include <queue>
using namespace std;
struct Edge
{
int from, to, cap, flow;
Edge(int f, int t, int c, int fl)
{
from = f; to = t; cap = c; flow = fl;
}
};
#define maxn 410
#define inf 0x3f3f3f3f
vector <Edge> edges;
vector <int> G[maxn];
int n, m, s, t;
int vis[maxn], cur[maxn], d[maxn];
void AddEdge(int from, int to, int cap)
{
edges.push_back(Edge(from, to, cap, 0));
edges.push_back(Edge(to, from, 0, 0));
m = edges.size();
G[from].push_back(m-2);
G[to].push_back(m-1);
}
bool bfs()
{
memset(vis, 0, sizeof(vis));
vis[s] = 1; d[s] = 0;
queue <int> q;
q.push(s);
while(!q.empty())
{
int x = q.front(); q.pop();
for(int i = 0; i < G[x].size(); i++)
{
Edge &e = edges[G[x][i]];
if(!vis[e.to] && e.cap > e.flow)
{
vis[e.to] = 1;
d[e.to] = d[x] + 1;
q.push(e.to);
}
}
}
return vis[t];
}
int dfs(int x, int a)
{
if(x == t || a == 0) return a;
int flow = 0, f;
for(int &i = cur[x]; i < G[x].size(); i++)
{
Edge &e = edges[G[x][i]];
if(d[e.to] == d[x]+1 && (f = dfs(e.to, min(a, e.cap - e.flow))) > 0)
{
e.flow += f;
edges[G[x][i]^1].flow -= f;
flow += f;
a -= f;
if(a == 0) break;
}
}
return flow;
}
int maxflow()
{
int flow = 0;
while(bfs())
{
memset(cur, 0, sizeof(cur));
flow += dfs(s, inf);
}
return flow;
}
int N, S, T;
int mp[maxn][maxn];
int main()
{
while(~scanf("%d%d%d", &N, &S, &T))
{
edges.clear();
for(int i = 1; i <= 2*N; i++) G[i].clear();
for(int i = 1; i <= N; i++)
{
for(int j = 1; j <= N; j++)
{
int a; scanf("%d", &a);
mp[i][j] = a;
if(i == j) AddEdge(i, N+j, 1);
else if(i != j && a) AddEdge(N+i, j, inf);
}
}
s = S+N; t = T; n = 2*N;
int ans = maxflow();
if(mp[S][T] == 1) { printf("NO ANSWER!\n"); continue;}
else printf("%d\n",  ans);

int total = ans;
int cnt = 0;
for(int p = 1; p <= N; p++)
{
if(cnt == total) break;
else if(p == S || p == T) continue;
edges.clear();
for(int i = 1; i <= 2*N; i++) G[i].clear();
for(int i = 1; i <= N; i++)
{
for(int j = 1; j <= N; j++)
{
if(i == p || j == p) continue;
if(i == j) AddEdge(i, N+j, 1);
else if(i != j && mp[i][j]) AddEdge(N+i, j, inf);
}
}
int flow = maxflow();
if(flow < ans)
{
if(cnt == 0) printf("%d", p);
else printf(" %d", p);
if(cnt == total-1) printf("\n");
cnt++; ans = flow;
for(int i = 1; i <= N; i++) mp[p][i] = mp[i][p] = 0;
}
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: