POJ1815

Problem : Friendship
Description : 一些人之间可以相互联系,但是当一个人出事后,那么与他有联系的人都会和他失去联系,同样,人与人之间的联系具有传递性,那么现在给你两个人,问你最少多少个人出事才能使得这两个人失去联系,注意,这两个人不可能出事。
Solution : 这是一个典型的求割点数目的问题,然而割点又可以通过拆点转化成割边来做,那么这个题就成了求最小割的问题了,我们的做法就是,枚举割点,如果这个点是割点那么在图中删掉这个点后跑一遍最大流后,最小割会变小,那么记录下这个点,如果最小割不变,那么这个点就不是必须的,把这个点又在图中恢复,这样下来就可以把所有的割点都找到了。拆点然后在这两个点之间连一条权值为1的边是为了每个人只会删除一次,相当于删掉这个点了,而且,这条边的在S,T之间的权值要设成INF,这是为了给出的两个人总不会出事。这条边的方向要和其他边的方向相反,这也是为了满足传递性。这题我开始用的邻接矩阵TLE,非得逼我用邻接表才AC。
Code(C++) :

#include <stdio.h>
#include <string.h>

#include <iostream>
#include <string>
#include <queue>

#define MIN(a,b) ((a)>(b)? (b):(a))

using namespace std;

const int SIZE=400+50;
const int INF=0x3f3f3f3f;

struct Node{
    int u,v;
    int cap;
    Node(){}
    Node(int U,int V,int Cap):
    u(U),v(V),cap(Cap){}
};

int src,des;
vector<int> G[SIZE];
Node e[SIZE*SIZE/2];
int d[SIZE];
int cur[SIZE];
int n;
int top;

int N,S,T;
bool had_erase[SIZE/2];
int MAP[SIZE/2][SIZE/2];
int t_M[SIZE/2][SIZE/2];

void addedge(int u,int v,int cap)
{
    G[u].push_back(top);
    e[top++]=Node(u,v,cap);
    G[v].push_back(top);
    e[top++]=Node(v,u,0);
}

void build()
{   
    int i,j;
    for(i=0;i<SIZE;i++)
        G[i].clear();
    top=0;
    n=2*N;
    src=0;
    des=n+1;
    addedge(src,S,INF);
    addedge(T+N,des,INF);
    for(i=1;i<=N;i++)
        addedge(i+N,i,1);
    addedge(S+N,S,INF);
    addedge(T+N,T,INF);
    for(i=1;i<=N;i++)
        for(j=1;j<=N;j++)
            if(MAP[i][j]&&i!=j)
                addedge(i,j+N,INF);
}

bool bfs(int src,int des)
{
    memset(d,-1,sizeof(d));
    queue<int> que;
    que.push(src);
    d[src]=0;
    while(!que.empty()){
        int now=que.front();
        que.pop();
        for(int i=0;i<G[now].size();i++){
            Node &tmp=e[G[now].at(i)];
            if(tmp.cap>0&&d[tmp.v]==-1)
                d[tmp.v]=d[now]+1,
                que.push(tmp.v);
        }
    }
    return d[des]>=0;
}

int dfs(int t,int sum,int des)
{
    if(t==des||!sum)
        return sum;
    int flow=0,f;
    for(int &i=cur[t];i<G[t].size();i++){
        Node &tmp=e[G[t].at(i)];
        if(d[tmp.v]==d[t]+1&&(f=dfs(tmp.v,MIN(sum,tmp.cap),des))>0){
            tmp.cap-=f;
            e[G[t].at(i)^1].cap+=f;
            sum-=f;
            flow+=f;
            if(!sum)
                break;
        }
    }
    return flow;
}

int DINIC(int src,int des)
{
    int sum=0;
    while(bfs(src,des)){
        memset(cur,0,sizeof(cur));
        sum+=dfs(src,INF,des);
    }
    return sum;
}

void work()
{
    int i,j;
    for(i=1;i<=N;i++)
        for(j=1;j<=N;j++)
            scanf("%d",&MAP[i][j]);
    if(MAP[S][T]){
        puts("NO ANSWER!");
        return ;
    }
    build();
    int tmp=DINIC(src,des);
    printf("%d\n",tmp);
    if(!tmp)
        return ;
    memset(had_erase,false,sizeof(had_erase));
    for(int L=1;L<=N;L++){
        if(L==S||L==T)
            continue;

        int i,j;
        for(i=1;i<=N;i++)
            for(j=1;j<=N;j++){
                t_M[i][j]=MAP[i][j];
                if(i==L||j==L)
                    MAP[i][j]=0;
            }
        build();
        int t=DINIC(src,des);
        if(t>=tmp){
            for(i=1;i<=N;i++)
                for(j=1;j<=N;j++)
                    MAP[i][j]=t_M[i][j];
        }
        else{
            --tmp;
            had_erase[L]=true;
        }
        if(!tmp)
            break;
    }
    int h[SIZE]={0};
    int top=0;
    for(i=1;i<=N;i++)
        if(had_erase[i])
            h[top++]=i;
    printf("%d",h[0]);
    for(i=1;i<top;i++)
        printf(" %d",h[i]);
    puts("");
}

int main()
{
    //freopen("in.data","r",stdin);
    while(~scanf("%d%d%d",&N,&S,&T))
        work();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值