zoukankan      html  css  js  c++  java
  • POJ 1815 Friendship(最小割)

    http://poj.org/problem?

    id=1815

    Friendship
    Time Limit: 2000MS   Memory Limit: 20000K
    Total Submissions: 9026   Accepted: 2534

    Description

    In modern society, each person has his own friends. Since all the people are very busy, they communicate with each other only by phone. You can assume that people A can keep in touch with people B, only if 
    1. A knows B's phone number, or 
    2. A knows people C's phone number and C can keep in touch with B. 
    It's assured that if people A knows people B's number, B will also know A's number. 

    Sometimes, someone may meet something bad which makes him lose touch with all the others. For example, he may lose his phone number book and change his phone number at the same time. 

    In this problem, you will know the relations between every two among N people. To make it easy, we number these N people by 1,2,...,N. Given two special people with the number S and T, when some people meet bad things, S may lose touch with T. Your job is to compute the minimal number of people that can make this situation happen. It is supposed that bad thing will never happen on S or T. 

    Input

    The first line of the input contains three integers N (2<=N<=200), S and T ( 1 <= S, T <= N , and S is not equal to T).Each of the following N lines contains N integers. If i knows j's number, then the j-th number in the (i+1)-th line will be 1, otherwise the number will be 0. 

    You can assume that the number of 1s will not exceed 5000 in the input. 

    Output

    If there is no way to make A lose touch with B, print "NO ANSWER!" in a single line. Otherwise, the first line contains a single number t, which is the minimal number you have got, and if t is not zero, the second line is needed, which contains t integers in ascending order that indicate the number of people who meet bad things. The integers are separated by a single space. 

    If there is more than one solution, we give every solution a score, and output the solution with the minimal score. We can compute the score of a solution in the following way: assume a solution is A1, A2, ..., At (1 <= A1 < A2 <...< At <=N ), the score will be (A1-1)*N^t+(A2-1)*N^(t-1)+...+(At-1)*N. The input will assure that there won't be two solutions with the minimal score. 

    Sample Input

    3 1 3
    1 1 0
    1 1 1
    0 1 1
    

    Sample Output

    1
    2
    

    Source



    题意:

    给出无向图,1表示有边,0表示没有边。如今要消去一些点,使得给出的A,B两点不相连,A和B不校区。问最少消去多少个点,并升序输出方案,有多种方案则输出 (A1-1)*N^t+(A2-1)*N^(t-1)+...+(At-1)*N最小的方案。

    分析:

    无向图中消去最少的点使两点割开。能够使用最小割求解。

    将一个点拆成入点和出点,之间连一条容量为一的边。

    图中原有的边依照出->入连一条容量为无穷大的边,A的出点为源点。B的入点为汇点。求出其最小割即为要消去的点的数量。

    详细方案的输出看上去比較复杂,细致分析实际上是一个N进制数。使这个数最小,就是其“字典序”最小。

    我们从小到大枚举每个点,假设将这个点(这个点拆出的边)去掉后的最小割小于原最小割,那么这个点(这个点拆出的边)属于最小割集。如此便可求出最后的结果。

    那么是不是每一个点都一定要枚举吗?我们考虑例如以下命题:最小割集中的边是满流边;其逆命题:满流边是最小割集中的边,别想了,这显然是否定的;其逆否命题:非满流边一定不属于最小割集,这才是我们要的命题。也就是说假设一个点拆出的边不满流,那它一定不构成最小割,所以这个点我们根本不用check。


    #include<cstdio>
    #include<iostream>
    #include<cstdlib>
    #include<algorithm>
    #include<ctime>
    #include<cctype>
    #include<cmath>
    #include<string>
    #include<cstring>
    #include<stack>
    #include<queue>
    #include<list>
    #include<vector>
    #include<map>
    #include<set>
    #define sqr(x) ((x)*(x))
    #define LL long long
    #define itn int
    #define INF 0x3f3f3f3f
    #define PI 3.1415926535897932384626
    #define eps 1e-10
    #define maxm 200007
    #define maxn 404
    
    using namespace std;
    
    int fir[maxn];
    int u[maxm],v[maxm],cap[maxm],flow[maxm],nex[maxm];
    int e_max;
    int iter[maxn],q[maxn],lv[maxn];
    
    void add_edge(int _u,int _v,int _w)
    {
        int e;
        e=e_max++;
        u[e]=_u;v[e]=_v;cap[e]=_w;
        nex[e]=fir[u[e]];fir[u[e]]=e;
        e=e_max++;
        u[e]=_v;v[e]=_u;cap[e]=0;
        nex[e]=fir[u[e]];fir[u[e]]=e;
    }
    
    void dinic_bfs(int s)
    {
        int f,r;
        memset(lv,-1,sizeof lv);
        q[f=r=0]=s;
        lv[s]=0;
        while(f<=r)
        {
            int x=q[f++];
            for (int e=fir[x];~e;e=nex[e])
            {
                if (cap[e]>flow[e] && lv[v[e]]<0)
                {
                    lv[v[e]]=lv[u[e]]+1;
                    q[++r]=v[e];
                }
            }
        }
    }
    
    int dinic_dfs(int _u,int t,int _f)
    {
        if (_u==t)  return _f;
        for (int &e=iter[_u];~e;e=nex[e])
        {
            if (cap[e]>flow[e] && lv[_u]<lv[v[e]])
            {
                int _d=dinic_dfs(v[e],t,min(_f,cap[e]-flow[e]));
                if (_d>0)
                {
                    flow[e]+=_d;
                    flow[e^1]-=_d;
                    return _d;
                }
            }
        }
    
        return 0;
    }
    
    int max_flow(int s,int t)
    {
    
        memset(flow,0,sizeof flow);
        int total_flow=0;
    
        for (;;)
        {
            dinic_bfs(s);
            if (lv[t]<0)    return total_flow;
            memcpy(iter,fir,sizeof iter);
            int _f;
    
            while ((_f=dinic_dfs(s,t,INF))>0)
                total_flow+=_f;
        }
    
        return total_flow;
    }
    
    int that_edge[maxn];
    
    int main()
    {
        #ifndef ONLINE_JUDGE
            freopen("/home/fcbruce/文档/code/t","r",stdin);
        #endif // ONLINE_JUDGE
    
        int n,_u,_v,_w,s,t;
    
        scanf("%d%d%d",&n,&_u,&_v);
        s=_u+n;t=_v;
        e_max=0;
        memset(fir,-1,sizeof fir);
    
        for (int i=1;i<=n;i++)
        {
            for (int j=1;j<=n;j++)
            {
                scanf("%d",&_w);
                if (!_w) continue;
                if (i==_u && j==_v || i==_v && j==_u)
                {
                    printf("NO ANSWER!
    ");
                    return 0;
                }
                add_edge(i+n,j,INF);
            }
        }
    
        for (int i=1;i<=n;i++)
        {
            that_edge[i]=e_max;
            add_edge(i,i+n,1);
        }
    
        int temp=max_flow(s,t);
        bool first=false;
        printf("%d
    ",temp);
    
        for (int i=1;i<=n && temp;i++)
        {
            if (i==s-n || i==t) continue;
            if (!flow[that_edge[i]]) continue;//最小割边一定满流,考虑逆否命题。不满流的边一定不是最小割边
            cap[that_edge[i]]=0;
    
            int k=max_flow(s,t);
            if (k<temp)
            {
                if (first) putchar(' ');
                first=true;
                printf("%d",i);
            }
            else
                cap[that_edge[i]]=1;
            temp=k;
        }
    
        putchar('
    ');
    
    
        return 0;
    }
    


  • 相关阅读:
    sqlplus edit 方式设置成vi
    oracle minus union intersect
    子查询中可以包含order by 子句--(在from里面)
    Linux 7 Ansible 初学 一个简单的 playbook 学习 yum 模块
    Linux 7 Ansible 初学 配置被控制机器的 YUM 源
    Linux 7 安装 Ansible 并作基本的配置
    Linux 7 安装开发工具包 Development Tools
    Linux 7.0 安装 mariadb 数据库及初始化,创建数据库,创建用户
    Linux bash初学 if语句
    Linux bash初学 case语句
  • 原文地址:https://www.cnblogs.com/wzzkaifa/p/6797693.html
Copyright © 2011-2022 走看看