poj 1815(最小割、割集)

题目链接:http://poj.org/problem?id=1815

思路:题目要求是剔除多少个点,可以将其转化为剔除多少条边,因此需要拆点,将点i拆成i,i+n,便容量为1,表示每个人起的传递作用只能是一次。然后就是枚举了,删除某条边,如果求出的最小割比原来的要小,说明减少的是割边集。

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #include<queue>
  6 using namespace std;
  7 #define MAXN 444
  8 #define MAXM 4444444
  9 #define inf 1<<30
 10 
 11 struct Edge{
 12     int v,cap,next;
 13 }edge[MAXM];
 14 
 15 int n,vs,vt,NE,NV;
 16 int head[MAXN];
 17 
 18 void Insert(int u,int v,int cap)
 19 {
 20     edge[NE].v=v;
 21     edge[NE].cap=cap;
 22     edge[NE].next=head[u];
 23     head[u]=NE++;
 24 
 25     edge[NE].v=u;
 26     edge[NE].cap=0;
 27     edge[NE].next=head[v];
 28     head[v]=NE++;
 29 }
 30 
 31 int level[MAXN],gap[MAXN];
 32 void bfs(int vt)
 33 {
 34     memset(level,-1,sizeof(level));
 35     memset(gap,0,sizeof(gap));
 36     level[vt]=0;
 37     gap[level[vt]]++;
 38     queue<int>que;
 39     que.push(vt);
 40     while(!que.empty()){
 41         int u=que.front();
 42         que.pop();
 43         for(int i=head[u];i!=-1;i=edge[i].next){
 44             int v=edge[i].v;
 45             if(level[v]!=-1)continue;
 46             level[v]=level[u]+1;
 47             gap[level[v]]++;
 48             que.push(v);
 49         }
 50     }
 51 }
 52 
 53 int pre[MAXN],cur[MAXN];
 54 int SAP(int vs,int vt)
 55 {
 56     bfs(vt);
 57     memset(pre,-1,sizeof(pre));
 58     memcpy(cur,head,sizeof(head));
 59     int maxflow=0,aug=inf;
 60     int u=pre[vs]=vs;
 61     gap[0]=NV;
 62     while(level[vs]<NV){
 63         bool flag=false;
 64         for(int &i=cur[u];i!=-1;i=edge[i].next){
 65             int v=edge[i].v;
 66             if(edge[i].cap>0&&level[u]==level[v]+1){
 67                 flag=true;
 68                 pre[v]=u;
 69                 u=v;
 70                 aug=min(aug,edge[i].cap);
 71                 if(v==vt){
 72                     maxflow+=aug;
 73                     for(u=pre[v];v!=vs;v=u,u=pre[u]){
 74                         edge[cur[u]].cap-=aug;
 75                         edge[cur[u]^1].cap+=aug;
 76                     }
 77                     aug=inf;
 78                 }
 79                 break;
 80             }
 81         }
 82         if(flag)continue;
 83         int minlevel=NV;
 84         for(int i=head[u];i!=-1;i=edge[i].next){
 85             int v=edge[i].v;
 86             if(edge[i].cap>0&&level[v]<minlevel){
 87                 minlevel=level[v];
 88                 cur[u]=i;
 89             }
 90         }
 91         if(--gap[level[u]]==0)break;
 92         level[u]=minlevel+1;
 93         gap[level[u]]++;
 94         u=pre[u];
 95     }
 96     return maxflow;
 97 }
 98 
 99 int map[MAXN][MAXN];
100 int cut[MAXN];
101 void Build()
102 {
103     NE=0;
104     memset(head,-1,sizeof(head));
105     for(int i=1;i<=n;i++){
106         if(cut[i])continue;
107         for(int j=1;j<=n;j++){
108             if(cut[j])continue;
109             if(i==j)Insert(i,i+n,1);
110             else if(map[i][j])Insert(i+n,j,inf);
111         }
112     }
113 }
114 
115 int main()
116 {
117     int maxflow,ans;
118     while(~scanf("%d%d%d",&n,&vs,&vt)){
119         for(int i=1;i<=n;i++)
120             for(int j=1;j<=n;j++)
121                 scanf("%d",&map[i][j]);
122         if(map[vs][vt]){
123             puts("NO ANSWER!");
124             continue;
125         }
126         vs+=n,NV=2*n;
127         memset(cut,0,sizeof(cut));
128         Build();
129         maxflow=SAP(vs,vt);
130         ans=0;
131         for(int i=1;i<=n;i++){
132             if(maxflow==0)break;
133             if(i==(vs-n)||i==vt)continue;
134             cut[i]=1;
135             Build();
136             int tmp=SAP(vs,vt);
137             if(tmp<maxflow){ ans++,maxflow=tmp; }
138             else cut[i]=0;
139         }
140         printf("%d\n",ans);
141         bool flag=true;
142         for(int i=1;i<=n;i++){
143             if(cut[i]){
144                 printf(flag?"%d":" %d",i);
145                 flag=false;
146             }
147         }
148         puts("");
149     }
150     return 0;
151 }
View Code

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值