题目链接:
http://poj.org/problem?id=1966
题意
有一个继电器网络,一些继电器由线相互连接,这个继电器网络有一个安全因子f
1.如果无论删除多少个点,这个网络仍连通,那么f=n
2.删除最少的点,使图不连通。
一个空图或者单个结点被认为是连通的。
思路
每个点拆边对于任意结点u,拆成一个入点u’,一个出点u”。并由u’到u”建立一条容量为1的边。若原图中,存在于u直接相连的v。在新建的图中,建立两条容量为无穷的边
(u”,v’) 和(v”,u’) 。
图建好后,固定一个源点,枚举汇点。这个汇点不直接与源点相连。枚举找出最小最小割。因为最小割是将源点和汇点分在两个不同的集合中,所以源点和汇点都不能删除,固定的源点在新图中,应该是源点拆点后的出点,同理,枚举的汇点应当是入点。这样流才不会经过源点和汇点的拆边。
#include<cstdio>// 最少删除几个点,使图不连通。拆点,固定源点枚举汇点求最小割 ,否则输出n
#include<queue>
#include<iostream>
#include<vector>
#include<map>
#include<cstring>
#include<string>
#include<set>
#include<stack>
#include<algorithm>
#define cle(a) memset(a,0,sizeof(a))
#define inf(a) memset(a,0x3f,sizeof(a))
#define ll long long
#define Rep(i,a,n) for(int i=a;i<=n;i++)
using namespace std;
const int INF = ( 2e9 ) + 2;
const ll maxn = 110;
int t[100];
struct Dinic
{
struct edge
{
int from,to,c,f;
edge(int getu,int getv,int getc,int getf)
{
from=getu;
to=getv;
c=getc;
f=getf;
}
};
int s,t,n;
int d[maxn];
int cur[maxn];
vector<edge> e;
vector<int> g[maxn];
void addedge(int u,int v,int c)
{
e.push_back(edge(u,v,c,0));
e.push_back(edge(v,u,0,0));
int m=e.size();
g[u].push_back(m-2);
g[v].push_back(m-1);
}
void init()
{
e.clear();
for(int i=0; i<=maxn; i++)
g[i].clear();
}
bool bfs()
{
queue<int> q;
q.push(s);
memset(d,0,sizeof(d));
d[s]=1;
while(!q.empty())
{
int u=q.front();
q.pop();
for(int i=0; i<g[u].size(); i++)
{
int v=e[g[u][i]].to;
int c=e[g[u][i]].c;
int f=e[g[u][i]].f;
if(!d[v]&&c-f>0)
{
d[v]=d[u]+1;
q.push(v);
}
}
}
return d[t];
}
int dfs(int u,int maxf,int t)
{
if(u==t)return maxf;
int ret=0;
for(int &i=cur[u]; i<g[u].size(); i++)
{
int c=e[g[u][i]].c-e[g[u][i]].f;
int v=e[g[u][i]].to;
int f;
if(d[u]+1==d[v]&&c)
{
f=dfs(v,min(maxf-ret,c),t);
e[g[u][i]].f+=f;
e[g[u][i]^1].f-=f;
ret+=f;
if(ret==maxf)return ret;
}
}
return ret;
}
int maxflow(int s,int t)
{
this->s=s;
this->t=t;
int flow=0;
while(bfs())
{
memset(cur,0,sizeof(cur));
int temp=dfs(s,INF,t);
flow+=temp;
}
return flow;
}
}dinic;
int main()
{
int n,m;
while(~scanf("%d%d",&n,&m))
{
dinic.init();
memset(t,0,sizeof(t));
for(int i=0;i<n;i++)
dinic.addedge(i,i+n,1);
for(int i=0;i<m;i++)
{
int u,v;
scanf(" (%d,%d)",&u,&v);
dinic.addedge(u+n,v,INF);
dinic.addedge(v+n,u,INF);
if(u==0)t[v]=1;
if(v==0)t[u]=1;
}
int ans=INF; //源点固定在0
for(int i=1;i<n;i++)
{
if(t[i])continue; //只枚举不与源点直接相连的点位汇点
for(int i=0;i<dinic.e.size();i++) // 跑完最大流后将流清空
dinic.e[i].f=0;
int mn=dinic.maxflow(n,i);
if(mn<ans)ans=mn;
}
if(ans==INF)
printf("%d\n",n);
else
printf("%d\n",ans);
}
}