HDU_3313_Key_Vertex(最小割)

题意:已给有向图,给定起点和终点S,T,问图中有多少个点去掉可以使S T不可达

思路:

按常规思路就是找一条最短路,最短路之外的所有点不符合条件,然后在最短路上搞搞就好了

为了加深一下最小割的理解就用最小割写了此题

拆点,拆点之间连容量为1的边,有向边连inf的边,最大流一下,显然关键点的拆点间的流是满流而且必须是最小割。

然后就从满流+最小割这两点判断就可以辣,若u -> v 不是最小割,那么残余网络上S必然可达v,所以在残余网络上bfsS的可达点。

/* **********************************************
Auther: kalili
Created Time: 2015/6/17 18:10:30
File Name   : HDU_3313_Key_Vertex最小割.cpp
*********************************************** */
//Accepted 3313 2386MS 19136K 5692 B C++
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <iostream>
#include <cstring>
#include <cmath>
#include <queue>
#include <stack>
#include <list>
#include <map>
#include <set>
#include <sstream>
#include <string>
#include <vector>
#include <cstdio>
#include <ctime>
#include <bitset>
#include <algorithm>
#define SZ(x) ((int)(x).size())
#define ALL(v) (v).begin(), (v).end()
#define foreach(i, v) for (__typeof((v).begin()) i = (v).begin(); i != (v).end(); ++ i)
#define REP(i,n) for ( int i=1; i<=int(n); i++ )
using namespace std;

const int inf = 0x3f3f3f3f;
const int N = 200000 +100;
const int M = 300000*10+10;
struct Edge
{
        int v,w,nxt;
        Edge(){}
        Edge(int v,int w,int nxt) : v(v),w(w),nxt(nxt) {}
}es[M];
int n,m;
int head[N];
int cnt;
void inline add_edge(int u,int v,int w)
{
        es[cnt]=Edge(v,w,head[u]);
        head[u]=cnt++;
        es[cnt]=Edge(u,0,head[v]);
        head[v]=cnt++;
}
int s,g;

int h[N],q[N],tail;
bool makeh(int s,int g)
{
        memset(h,0,sizeof(h));
        h[s]=1;
        tail=0;
        q[tail++]=s;
        for(int i=0;i<tail;i++)
        {
                int u = q[i];
                if(u ==  g) return true;
                for(int i = head[u];~i;i = es[i].nxt)
                {
                        int v = es[i].v,w = es[i].w;
                        if(w&&h[v] == 0) q[tail++]=v,h[v] = h[u]+1;
                }
        }
        return false;
}
int dfs(int u,int g,int maxf)
{
        if(u == g) return maxf;
        int ans=0;
        for(int i = head[u];~i;i = es[i].nxt)
        {
                int v = es[i].v,w = es[i].w;
                if(w&&h[v] == h[u]+1)
                {
                        int f = dfs(v,g,min(maxf-ans,w));
                        ans += f;
                        es[i].w -= f;
                        es[i^1].w += f;
                        if(ans == maxf) return ans;
                }
        }
        if(ans == 0) h[u]=-1;
        return ans;
}
int Dinic(int s,int g)
{
        int ans=0;
        while(makeh(s,g)) ans+=dfs(s,g,inf);
        return ans;
}
bool vis[N];
int que[N],top;
void bfs(int src)
{
        que[top++] = src;
        vis[src]=1;
        for(int i = 0;i < top; i++)
        {
                int u=que[i];
                for(int i = head[u]; ~i ;i = es[i].nxt)
                {
                        int v = es[i].v,w = es[i].w;
                        if(w&&vis[v] == 0) que[top++]=v,vis[v]=1;
                }
        }
}
void ini()
{
        cnt=0;
        memset(head,-1,sizeof(head));
}
int main()
{
        while(~scanf("%d%d",&n,&m))
        {
                ini();
                REP(i,m)
                {
                        int u,v;
                        scanf("%d%d",&u,&v);
                        add_edge(u+n,v,inf);
                }
                scanf("%d%d",&s,&g);
                for(int i=0;i<n;i++)
                {
                        if(i==s||i==g) add_edge(i,i+n,2);
                        else add_edge(i,i+n,1);
                }
                int ans=Dinic(s,g+n);
                if(ans == 2) puts("2");
                if(ans == 0) printf("%d\n",n);
                if(ans == 1)
                {
                        int cnt=0;
                        int src=s;
                        es[head[s]].w = es[head[g]].w=0;
                        memset(vis,0,sizeof(vis));
                        while(true)
                        {
                                top=0;
                                bfs(src);
                                bool flag=0;
                                for(int i =0 ; i < top; i++)
                                {
                                        int u=que[i];
                                        if(flag) break;
                                        for(int i = head[u];~i;i = es[i].nxt)
                                        {
                                                if(i&1) continue;
                                                int v=es[i].v,w=es[i].w;
                                                if(w == 0 && vis[v] == 0)
                                                {
                                                        cnt++;
                                                        src = v;
                                                        flag=1;
                                                        break;
                                                }
                                        }
                                }
                                if(src==g+n) break;
                        }
                        printf("%d\n",cnt);
                }

        }

}
时间: 2024-11-01 16:12:34

HDU_3313_Key_Vertex(最小割)的相关文章

【BZOJ2039】【2009国家集训队】人员雇佣 [最小割]

人员雇佣 Time Limit: 20 Sec  Memory Limit: 259 MB[Submit][Status][Discuss] Description 作为一个富有经营头脑的富翁,小L决定从本国最优秀的经理中雇佣一些来经营自己的公司.这些经理相互之间合作有一个贡献指数,(我们用Ei,j表示i经理对j经理的了解程度),即当经理i和经理j同时被雇佣时,经理i会对经理j做出贡献,使得所赚得的利润增加Ei,j.当然,雇佣每一个经理都需要花费一定的金钱Ai,对于一些经理可能他做出的贡献不值得

hdoj 4289 Control 【拆点 求最小割】

Control Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2295    Accepted Submission(s): 961 Problem Description You, the head of Department of Security, recently received a top-secret informati

There is a war (hdu 2435 最小割+枚举)

There is a war Time Limit: 5000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 970    Accepted Submission(s): 277 Problem Description There is a sea. There are N islands in the sea. There are some directional

HDU 3657 Game(取数 最小割)经典

Game Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1065    Accepted Submission(s): 449 Problem Description onmylove has invented a game on n × m grids. There is one positive integer on each g

POJ2914 Minimum Cut【全局最小割】【Stoer-Wangner】

题目链接: http://poj.org/problem?id=2914 题目大意: 提一个无向有重边的图,有重边的边权累加起来,求全局最小割. 思路: 一个无向连通图,去掉一个边集可以使其变成两个连通分量则这个边集就是割集.最小割 集当然就是权和最小的割集. 这是一个最简单的全局最小割模板题.直接套上模板就可以了.来说说Stoer-Wangner算 法吧. Stoer-Wangner算法: 对于图中的任意两个顶点u和v,若u,v属于最小割的同一个集合中,那么僵顶点u和顶点 v合并后并不影响图的

HDU 3035 War(对偶图求最小割)

HDU 3035 War 题目链接 题意:根据图那样,给定一个网络,要求阻断s到t,需要炸边的最小代价 思路:显然的最小割,但是也显然的直接建图强行网络流会超时,这题要利用平面图求最小割的方法,把每一块当成一个点,共有边连边,然后每一个路径就是一个割,然后最短路就是最小割了 代码: #include <cstdio> #include <cstring> #include <vector> #include <queue> using namespace s

ZOJ 2587 Unique Attack 判断最小割是否唯一

很裸的判断最小割是否唯一.判断方法是先做一遍最大流求最小割,然后从源点和汇点分别遍历所有能够到达的点,看是否覆盖了所有的点,如果覆盖了所有的点,那就是唯一的,否则就是不唯一的. #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <climits> #include <string> #include <iostr

AHOI2009最小割

1797: [Ahoi2009]Mincut 最小割 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1072  Solved: 446[Submit][Status] Description A,B两个国家正在交战,其中A国的物资运输网中有N个中转站,M条单向道路.设其中第i (1≤i≤M)条道路连接了vi,ui两个中转站,那么中转站vi可以通过该道路到达ui中转站,如果切断这条道路,需要代价ci.现在B国想找出一个路径切断方案,使中转站s不能到

bzoj1412-网络流最小割

狼爱上羊啊爱的疯狂,谁让他们真爱了一场:狼爱上羊啊并不荒唐,他们说有爱就有方向......” Orez听到这首歌,心想:狼和羊如此和谐,为什么不尝试羊狼合养呢?说干就干! Orez的羊狼圈可以看作一个n*m个矩阵格子,这个矩阵的边缘已经装上了篱笆.可是Drake很快发现狼再怎么也是狼,它们总是对羊垂涎三尺,那首歌只不过是一个动人的传说而已.所以Orez决定在羊狼圈中再加入一些篱笆,还是要将羊狼分开来养. 通过仔细观察,Orez发现狼和羊都有属于自己领地,若狼和羊们不能呆在自己的领地,那它们就会变