Time Limit: 1000MS | Memory Limit: 30000K | |
Total Submissions: 4956 | Accepted: 2292 |
Description
Input
Output
Sample Input
0 0 1 0 3 3 (0,1) (0,2) (1,2) 2 0 5 7 (0,1) (0,2) (1,3) (1,2) (1,4) (2,3) (3,4)
Sample Output
0 1 3 0 2
Hint
The first data set encodes an empty network, the second data set corresponds to a network with a single relay, and the following three data sets encode the nets shown in figure 1.
题解:
大致的题意就是给定一个无向图,求最少去掉多少个点,可以使剩下的图不联通。如果无论删多少个点,剩下的图仍联通,则输出点数N。点数<=50。
若无向图不连通,则图中必有两个点不连通。可以枚举这两个点S和T,求在剩下的N-2的点中最少去掉多少个点能使图不连通。在每次枚举的过程中取最小值即为答案。
“去掉最少的的点使S,T不连通”,容易想到网络流的最大流最小割。但不同的是最小割球的是“边”,而这道题求的是“点”。所以做这道题有一个重要的技巧:拆点
拆点,顾名思义就是把点拆开,所以我们可以按照下面的方法构建一个网络:
1.把原来无向图的点差成x和x+n两个点。
2.对每一个点连接一条有向边(x,x+n),容量为1.
3.对于原无向图中的每一条边(x,y),在网络中连有向边(x+n,y),(y,x+n),容量为正无穷。
以S为源点,T为汇点,求最小割即最大流,答案即为最少需要去掉的点数。
将点拆成两个点,并连接一条有向边,容量为1,这样要想经过这个点就相当于必须流经这条边。所以删去一个点,就等价于断开这条边。
代码(16ms):
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
const int inf=1e9+7;
const int Max=1e3+7;
int size,ans,n,m,minn,s,t;
int depth[Max],first[Max],map[55][55];
struct shu{int to,len,next;};
shu bian1[Max],bian[Max];
inline int get_int()
{
int x=0,f=1;
char c;
for(c=getchar();(!isdigit(c))&&(c!='-');c=getchar());
if(c=='-') {f=-1;c=getchar();}
for(;isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+c-'0';
return x*f;
}
inline void clean()
{
size=1;
memset(first,0,sizeof(first));
memset(bian1,0,sizeof(bian1));
memset(bian,0,sizeof(bian));
memset(map,0,sizeof(map));
}
inline void build(int x,int y,int z)
{
size++;
bian1[size].next=first[x];
first[x]=size;
bian1[size].to=y;
bian1[size].len=z;
}
inline bool bfs()
{
memset(depth,0,sizeof(depth));
queueq;
q.push(s);
depth[s]=1;
while(!q.empty())
{
int point=q.front();
q.pop();
for(int u=first[point];u;u=bian[u].next)
{
if(!depth[bian[u].to]&&bian[u].len)
{
depth[bian[u].to]=depth[point]+1;
q.push(bian[u].to);
}
}
}
return depth[t];
}
inline int dinic(int point,int flow)
{
int sum=0;
if(point==t) return flow;
for(int u=first[point];u&&sum