poj 1815 最小割+枚举

题意:给一个无向图,求最少删除多少个点,使得从S到T不连通,并输出字典序最小的方案数。

思路:拆点,从S到T跑一遍最小割,求出最少删除的点数。

关键是如何求字典序最小的方案,可以从1到n枚举每个点(拆成的边)是否可以在最小割中,即把这个点所连的所有边断掉,再跑一遍最小割。如果最小割减小,就把这个点从割集中删除;否则,把这个点恢复。

代码:

  1 #include<cstdio>
  2 #include<algorithm>
  3 
  4 using namespace std;
  5 typedef long long ll;
  6 
  7 const int N=210;
  8 const int M=1e5+10;
  9 const int inf=0x3f3f3f3f;
 10 
 11 int head[N<<1],to[M],nxt[M],w[M];
 12 int cur[N<<1],d[N<<1],gap[N<<1];
 13 int tot;
 14 
 15 bool vis[N];
 16 
 17 int g[N][N];
 18 
 19 int n,s,t;
 20 int ans[N];
 21 
 22 inline void add(int u,int v,int x){
 23     to[++tot]=v,nxt[tot]=head[u],w[tot]=x,head[u]=tot;
 24     to[++tot]=u,nxt[tot]=head[v],w[tot]=0,head[v]=tot;
 25 }
 26 
 27 int dfs(int u,int in){
 28     if(u==t) return in;
 29     int out=0;
 30     for(int &i=cur[u];i;i=nxt[i]){
 31         int v=to[i];
 32         if(d[v]+1==d[u]){
 33             int res=dfs(v,min(in,w[i]));
 34             w[i]-=res,w[i^1]+=res;
 35             in-=res,out+=res;
 36             if(!in) return out;
 37         }
 38     }
 39     if(!(--gap[d[u]])) d[s]=(n<<1)+1;
 40     ++gap[++d[u]],cur[u]=head[u];
 41     return out;
 42 }
 43 
 44 int main()
 45 {
 46     scanf("%d%d%d",&n,&s,&t);
 47     for(int i=1;i<=n;i++){
 48         for(int j=1;j<=n;j++){
 49             scanf("%d",&g[i][j]);
 50         }
 51     }
 52     if(g[s][t]){
 53         printf("NO ANSWER!\n");
 54         return 0;
 55     }
 56     tot=1;
 57     for(int i=1;i<=n;i++){
 58         if(i==s||i==t) add(i,i+n,inf);
 59         else add(i,i+n,1);
 60     }
 61     for(int i=1;i<=n;i++){
 62         for(int j=i+1;j<=n;j++){
 63             if(g[i][j]){
 64                 add(i+n,j,inf);
 65                 add(j+n,i,inf);
 66             }
 67         }
 68     }
 69     int res=0;
 70     while(d[s]<=(n<<1)) res+=dfs(s,inf);
 71     int cnt=0;
 72     for(int i=1;i<=n;i++){
 73         if(i==s||i==t) continue;
 74         vis[i]=1;
 75         tot=1;
 76         for(int j=1;j<=(n<<1);j++){
 77             head[j]=0;
 78             cur[j]=gap[j]=d[j]=0;
 79         }
 80         for(int j=1;j<=n;j++){
 81             if(!vis[j]){
 82                 if(j==s||j==t) add(j,j+n,inf);
 83                 else add(j,j+n,1);
 84             }
 85         }
 86         for(int j=1;j<=n;j++){
 87             if(!vis[j])
 88             for(int k=j+1;k<=n;k++){
 89                 if(g[j][k]&&!vis[k]){
 90                     add(j+n,k,inf);
 91                     add(k+n,j,inf);
 92                 }
 93             }
 94         }
 95         int tmp=0;
 96         while(d[s]<=(n<<1)) tmp+=dfs(s,inf);
 97         if(tmp<res){
 98             res=tmp;
 99             ans[++cnt]=i;
100         }
101         else vis[i]=0;
102     }
103     printf("%d\n",cnt);
104     for(int i=1;i<=cnt;i++){
105         printf("%d%c",ans[i],i==cnt? '\n':' ');
106     }
107     return 0;
108 }

 

posted @ 2020-10-02 19:47  --HY--  阅读(152)  评论(0编辑  收藏  举报