poj1966Cable TV Network——无向图最小割(最大流)

题目:http://poj.org/problem?id=1966

把一个点拆成入点和出点,之间连一条边权为1的边,跑最大流即最小割;

原始的边权赋成inf防割;

枚举源点和汇点,直接相邻的两个点不必枚举;

注意:1、源点为枚举点i的出点,汇点为枚举点j的入点;

   2、读入方式,免空格;

   3、在dinic跑最大流的过程中,会改变边权,因此每次枚举都要复制一组边跑最大流,以免影响后面;

另:数据中的点从0开始,所以读入的时候++来使用。

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
queue<int>q;
int n,m,head[105],cur[105],ct=1,inf=1e9,ans,d[105];
bool sid[55][55];
struct N{
    int to,next,w;
    N(int t=0,int n=0,int ww=0):to(t),next(n),w(ww) {}
}edge[6005],ed[6005];
void add(int x,int y,int z)
{
    ed[++ct]=N(y,head[x],z);head[x]=ct;
    ed[++ct]=N(x,head[y],0);head[y]=ct;
}
bool bfs(int s,int t)
{
    memset(d,0,sizeof d);
    while(q.size())q.pop();
    d[s]=1;q.push(s);
    while(q.size())
    {
        int x=q.front();q.pop();
        for(int i=head[x];i;i=edge[i].next)
        {
            int u=edge[i].to;
            if(!d[u]&&edge[i].w)
            {
                d[u]=d[x]+1;
                q.push(u);
            }
        }
    }
    return d[t];
}
int dfs(int x,int f,int t)
{
    if(x==t)return f;
    int res=0;
    for(int i=cur[x];i;i=edge[i].next)
    {
        int u=edge[i].to;
        if(d[u]==d[x]+1&&edge[i].w)
        {
            int tmp=dfs(u,min(edge[i].w,f-res),t);
            edge[i].w-=tmp;
            edge[i^1].w+=tmp;
            res+=tmp;
            if(edge[i].w)cur[x]=i;
            if(res==f)return f;
        }
    }
    if(!res)d[x]=0;
    return res;
}
int dinic(int s,int t)
{
    memcpy(edge,ed,sizeof ed);//!!!
    int res=0;
    while(bfs(s+n,t))
    {
        for(int i=0;i<=2*n;i++)cur[i]=head[i];
        res+=dfs(s+n,inf,t);
    }
    return res;
}
int main()
{
    while(scanf("%d%d",&n,&m)==2)
    {
        if(!n||n==1)
        {
            printf("%d\n",n);
            continue;
        }
        if(!m)
        {
            printf("0\n");
            continue;
        }
        ct=1;ans=inf;
        memset(head,0,sizeof head);
        memset(sid,0,sizeof sid);
        for(int i=1;i<=n;i++)add(i,i+n,1);
//        char dc=0;
        for(int i=1;i<=m;i++)
        {
//            dc=0;
//            while(dc!=‘(‘)scanf("%c",&dc);
            int x,y;
            scanf(" (%d,%d)",&x,&y);//或者采用注释方法读入,这里为 scanf("%d,%d",&x,&y);
            x++;y++;//
            sid[x][y]=1;sid[y][x]=1;
            add(x+n,y,inf);
            add(y+n,x,inf);
        }
        for(int i=1;i<=n;i++)
            for(int j=i+1;j<=n;j++)
                if(!sid[i][j])ans=min(ans,dinic(i,j));
        if(ans==inf)ans=n;
        printf("%d\n",ans);
//        dc=0;
//        while(dc!=‘)‘)scanf("%c",&dc);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/Zinn/p/8620780.html

时间: 2024-09-30 21:09:03

poj1966Cable TV Network——无向图最小割(最大流)的相关文章

UVA-1660 Cable TV Network (最小割)

题目大意:给一张n个点.m条边的无向图,求最小点割集的基数. 题目分析:求无向图最小点割集的基数可以变成求最小割.考虑单源s单汇t的无向图,如果要求一个最小点集,使得去掉这个点集后图不再连通(连通分量数目增多),只需将每个点拆成两个(入点和出点),并且之间连一条容量为1的弧,其他弧不变,在新网络上求最小割便得到这个最小点集的基数.但是本题无源无汇,可以指定一个点作为源点,枚举其它的点作为汇点,求得n-1个点集基数,取最小的便是答案.要注意每次枚举都要重新建图. 代码如下: # include<i

ZOJ 2182 Cable TV Network(无向图点割-最大流)

题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2182 题意:给出一个无向图,问最少删掉多少个顶点之后图变得不连通? 思路:将原图每个点拆点(i,i+n),连边<i,i+n,1>,对原图的边(u,v),连边<u+n,v,INF>,<v+n,u,INF>.然后对于每对顶点(i,j)跑最大流(i+n,j).所有最大流的最小值即为答案. struct node { int v,cap,nex

zoj 2676 Network Wars(最小割,01分数规划)

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2676 大致题意:给出一个带权无向图,每条边有一个边权wi,求将S和T分开的一个割边集C,使得该割边集的平均边权最小,即最小化∑wi / |C| . 详见amber关于最小割模型的论文 思路:amber论文中详细讲解了如何转化成函数及建图,值得注意的是当边被重新赋权后,对于wi < 0 的边权,该边必然在最小割中,不必再建边,直接加入最大流中即可,因为求最小割时边权都为正值

ZOJ3792_Romantic Value(网络流/最小割=最大流/找割边)

解题报告 题目传送门 题意: 给出一个无向图,以及起点与终点.要删除一些边使得起点与终点不连通,在删掉边的权值之和最小的情况下要求删除的边数尽量少. 求出一个比值:剩余边数权值和/删除的边数. 思路: 明显的让起点终点达不到就是一个最小割,用最大流可以求出. 但是求割边边数就不会了,没做过最小割的求割边问题. 割边一定是残留网络中零流的边,但零流不一定是割边. 飞神的想法很奇特.链接传送 可以把残留网络的零流的边设成容量为1,其他设成无穷,再求一次最大流.最后流量一定等于割边边数 另外: 还有一

【BZOJ-1797】Mincut 最小割 最大流 + Tarjan + 缩点

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

求无向图最小割

先解释下名词的意思. 无向图的割:就是去掉一些边,使得原图不连通,最小割就是要去掉边的数量最小. 解决这个问题的常用办法就是Stoer-Wagner 算法: 先说下这个算法的步骤后面给出证明: 1.min=MAXINT,固定一个顶点P 2.从点P用类似prim的s算法扩展出"最大生成树",记录最后扩展的顶点和最后扩展的边 3.计算最后扩展到的顶点的切割值(即与此顶点相连的所有边权和),若比min小更新min 4.合并最后扩展的那条边的两个端点为一个顶点 5.转到2,合并N-1次后结束

Hdu 3691 Nubulsa Expo(无向图最小割)

题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=3691 思路:无向图最小割模板题. 流量最小且汇点自定,则可在最小割T集中任选一点当做汇点. #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define debu using namespace std; const int maxn=350; const in

Destroying The Graph 最小点权集--最小割--最大流

Destroying The Graph 构图思路: 1.将所有顶点v拆成两个点, v1,v2 2.源点S与v1连边,容量为 W- 3.v2与汇点连边,容量为 W+ 4.对图中原边( a, b ), 连边 (a1,b2),容量为正无穷大 则该图的最小割(最大流)即为最小花费. 简单证明: 根据ST割集的定义,将顶点分成两个点集.所以对于原图中的边(a,b),转换成 S->a1->b2->T. 则此时路径必定存在 一条割边,因为a1->b2为无穷大,所以割边必定是 S->a1

POJ3469_Dual Core CPU(网络流/最小割=最大流/模版)----Dinic模版2.0

解题报告 题目传送门 题意: 双核CPU,n个模块,每个模块必须运行在某个CPU核心上,每个模块在cpu单核的消耗A和B,M对模块要共享数据,如果在同一个核心上不用消耗,否则需要耗费.安排N个模块,使得总耗费最小 思路: 将两个cpu核心看成源点和汇点,其他模块分别与源点汇点连线(表示每个模块可以在任意cpu上运行),m对模块分别连双向边,要使得模块只能在一个cpu上运行,就是找到一个割,源点和汇点必不联通,耗费最少就是最小割,最小割最大流原理转换成求最大流. 这题数据大,没优化TLE了,加了两