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 }