POJ - 1815,字典序最小割集

Friendship

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.

题意:有n个点,用矩阵形式表示出它们之间的边,当拆掉一个点时与之相邻的边全部被拆除,问现在想让两个点S,T不联通,至少要拆几个点(S,T不能拆),并输出这些点的标号,当有多组答案时输出字典序最小的那一组
思路:首先将非S,T的点i拆成左右两点i与i+n,两点间连一条容量为1的边保证这个点只会被拆一次,然后所有与i有连边的点u由u的右部点向i的左部点连边(即每个左部点只有入度,右部点只有出度,S,T的左部点和右部点相同,可以保证S,T不会被割开),跑S到T的最大流即为最小割
暴力做法: 现要求出字典序最小的割集,那么我们从小到大枚举所有点(除S,T),当枚举到i时将i与i+n之间的边拆除,跑最大流看流量是否减小,如果减小说明这个点在割集中,将它加入割集,反复进行上述操作(记得每次将已加入割集的点拆除)
优化方法: https://blog.csdn.net/xing_mo/article/details/103995004

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>//
#define MAXN 410
#define MAXM 40010
using namespace std;
const int INF = 0x3f3f3f3f;
int head[MAXN],tot;
struct edge
{
    int v,c,nxt;
}edg[MAXM << 1];
inline void addedg(int u,int v,int c)
{
    edg[tot].v = v;
    edg[tot].c = c;
    edg[tot].nxt = head[u];
    head[u] = tot++;
}
inline void add(int u,int v,int c)
{
    addedg(u,v,c);
    addedg(v,u,0);
}
int n,d[MAXN];
inline bool bfs(int s,int t)
{
    queue<int> qu;
    memset(d,-1,sizeof(int)*(n+n+2));
    qu.push(s);
    d[s] = 0;
    int v;
    while(!qu.empty())
    {
        int u = qu.front();
        qu.pop();
        for(int i = head[u];i != -1;i = edg[i].nxt)
        {
            v = edg[i].v;
            if(edg[i].c > 0 && d[v] == -1)
                d[v] = d[u]+1,qu.push(v);
        }
    }
    return d[t] != -1;
}
int dfs(int u,int flow,int t)
{
    if(u == t)
        return flow;
    int res = 0;
    for(int i = head[u];i != -1;i = edg[i].nxt)
    {
        int v = edg[i].v;
        if(edg[i].c > 0 && d[v] == d[u] + 1)
        {
            int tmp = dfs(v,min(flow,edg[i].c),t);
            flow -= tmp;
            res += tmp;
            edg[i].c -= tmp;
            edg[i^1].c += tmp;
            if(flow == 0)
                break;
        }
    }
    if(res == 0)
        d[u] = -1;
    return res;
}
inline void init()
{
    memset(head,-1,sizeof(int)*(n+n+2));
    tot = 0;
}
int mp[205][205],s,t,id[MAXN];
int main()
{
    while(~scanf("%d%d%d",&n,&s,&t))
    {
        for(int i = 1;i <= n;++i)
            for(int j = 1;j <= n;++j)
                scanf("%d",&mp[i][j]);
        if(mp[s][t])
        {
            printf("NO ANSWER!\n");
            continue;
        }
        init();
        for(int i = 1;i <= n;++i)
            for(int j = 1;j <= n;++j)
                if(mp[i][j]&&i!=s&&i != j)
                    add(i+n,j,1);
                else if(mp[i][j] && i != j)
                    add(i,j,1);
        for(int i = 1;i <= n;++i)
            if(i != s && i != t)
                id[i] = tot,add(i,i+n,1);
        int ans = 0;
        while(bfs(s,t))
            ans += dfs(s,INF,t);
        vector<int> ve;
        for(int i = 1;i <= n;++i)
        {
            if(i != s && i != t)
            {
                for(int j = 0;j < tot;++j)
                    if(j & 1)
                        edg[j].c = 0;
                    else
                        edg[j].c = 1;
                edg[id[i]].c = 0;
                for(int j = 0;j < ve.size();++j)
                    edg[id[ve[j]]].c = 0;
                int tmp = 0;
                while(bfs(s,t))
                    tmp += dfs(s,INF,t);
                if(tmp < ans)
                    ve.push_back(i),ans = tmp;
            }
        }
        printf("%d\n",ve.size());
        for(int i = 0;i < ve.size();++i)
            printf("%d ",ve[i]);
        printf("\n");
    }
    return 0;
}
/*
5 1 3
1 1 0 1 0
1 1 1 1 0
0 1 1 0 1
1 0 0 1 1
0 0 1 1 1

5 1 3
1 1 0 0 1
1 1 1 0 1
0 1 1 1 1
0 0 1 1 1
1 0 1 1 1

7 5 2
1 1 0 0 1 1 1
1 1 1 1 0 1 1
0 1 1 1 1 0 1
0 1 1 1 1 1 0
1 0 1 1 1 0 0
1 1 0 1 0 1 0
1 1 1 0 0 0 1
*/
发布了50 篇原创文章 · 获赞 3 · 访问量 3109

猜你喜欢

转载自blog.csdn.net/xing_mo/article/details/103991994