POJ 1815 最小割

题意:

n个人的两两关系矩阵,如果a认识b,则b认识a,且认识有传递性。给出一个s和一个t,问想让s不认识t,最少需要去掉多少人。
如果有解,输出字典序最小的解。

题解:

请特别注意0与NO ANSWER!的区别!

具体做法是:拆点限流,先求一次最小割为ans,然后从小到大枚举删除的点,重新建图再做最小割,如果当前结果比ans小,则更新ans,并把这个节点打上vis标记。

ps:已经打上vis标记的点不再参与之后重建图时

 

View Code
  1 #include <cstring>
  2 #include <cstdio>
  3 #include <cstdlib>
  4 #include <iostream>
  5 #include <algorithm>
  6 
  7 #define N 500
  8 #define M 40000
  9 #define INF 1e9
 10 
 11 using namespace std;
 12 
 13 int head[N],to[M],next[M],len[M];
 14 int q[M*4],layer[N];
 15 bool map[N][N],vis[N];
 16 int n,S,T,tt,ss,cnt;
 17 
 18 inline void add(int u,int v,int w)
 19 {
 20     to[cnt]=v; len[cnt]=w; next[cnt]=head[u]; head[u]=cnt++;
 21     to[cnt]=u; len[cnt]=0; next[cnt]=head[v]; head[v]=cnt++;
 22     //printf("%d   %d   %d\n",u,v,w);
 23 }
 24 
 25 inline bool read()
 26 {
 27     memset(head,-1,sizeof head); cnt=0;
 28     memset(vis,0,sizeof vis);
 29     memset(map,0,sizeof map);
 30     S=0; T=n+n+1;
 31     
 32     for(int i=1;i<=n;i++)
 33         for(int j=1;j<=n;j++)
 34             scanf("%d",&map[i][j]);
 35     if(map[ss][tt]) return false;
 36     
 37     add(S,ss,INF); add(tt+n,T,INF);
 38     for(int i=1;i<=n;i++)
 39     {
 40         if(i==ss||i==tt) add(i,i+n,INF);
 41         else add(i,i+n,1);
 42     }
 43     for(int i=1;i<=n;i++)
 44         for(int j=1;j<=n;j++)
 45             if(map[i][j]&&i!=j) add(i+n,j,INF);
 46     return true;
 47 }
 48 
 49 inline void rebuild(int u)
 50 {
 51     memset(head,-1,sizeof head); cnt=0;
 52     add(S,ss,INF); add(tt+n,T,INF);
 53     for(int i=1;i<=n;i++)
 54     {
 55         if(i==ss||i==tt) add(i,i+n,INF);
 56         else if(i!=u&&!vis[i]) add(i,i+n,1);
 57     }
 58     for(int i=1;i<=n;i++)
 59     {
 60         if(i==u||vis[i]) continue;
 61         for(int j=1;j<=n;j++)
 62             if(map[i][j]&&j!=u&&i!=j&&!vis[j])
 63                 add(i+n,j,INF);
 64     }
 65 }
 66 
 67 inline bool bfs()
 68 {
 69     memset(layer,-1,sizeof layer);
 70     int h=1,t=2,sta;
 71     q[1]=S; layer[S]=0;
 72     while(h<t)
 73     {
 74         sta=q[h++];
 75         for(int i=head[sta];~i;i=next[i])
 76             if(len[i]&&layer[to[i]]<0)
 77             {
 78                 layer[to[i]]=layer[sta]+1;
 79                 q[t++]=to[i];
 80             }
 81     }
 82     return layer[T]!=-1;
 83 }
 84 
 85 inline int find(int u,int cur_flow)
 86 {
 87     if(u==T) return cur_flow;
 88     int res=0,tmp;
 89     for(int i=head[u];~i&&res<cur_flow;i=next[i])
 90         if(len[i]&&layer[to[i]]==layer[u]+1)
 91         {
 92             tmp=find(to[i],min(cur_flow-res,len[i]));
 93             len[i]-=tmp; len[i^1]+=tmp; res+=tmp;
 94         }
 95     if(!res) layer[u]=-1;
 96     return res;
 97 }
 98 
 99 inline void go()
100 {
101     int ans=0,num=0;
102     while(bfs()) ans+=find(S,INF);
103     if(!ans)
104     {
105         puts("0");
106         return;
107     }
108     for(int i=1,res;i<=n;i++)
109         if(i!=ss&&i!=tt)
110         {
111             res=0;
112             rebuild(i);
113             while(bfs()) res+=find(S,INF);
114             if(ans>res) vis[i]=true,num++,ans=res;
115         }
116     printf("%d\n",num);
117     for(int i=1,sg=0;i<=n;i++)
118         if(vis[i])
119         {
120             if(!sg) sg=true,printf("%d",i);
121             else printf(" %d",i);
122         }
123     puts("");
124 }
125 
126 int main()
127 {
128     while(scanf("%d%d%d",&n,&ss,&tt)!=EOF)
129     {
130         if(!read()) puts("NO ANSWER!");
131         else go();
132     }
133     return 0;
134 }

 

posted @ 2013-01-06 22:14  proverbs  阅读(183)  评论(0编辑  收藏  举报