POJ1815

来源:互联网 发布:hbuilder下载 mac 编辑:程序博客网 时间:2024/04/30 14:08

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;}
0 0
原创粉丝点击