POJ1815 Friendship(字典序最小最小割割边集)
看了题解。当时也觉得用邻接矩阵挺好写的,直接memset;然而邻接矩阵不懂得改,于是就放开那个模板,写了Dinic。。
方法是,按字典序枚举每一条满流的边,然后令其容量减1,如果最大流改变了,这条边就是属于某个最小割;接下来一直重复下去,直到得到一个割边集,而它自然是字典序最小的。
我在每次某条边容量减1后都重新计算一遍最大流,简单。。其实我知道是有这么一回事,把边容量减1后可以利用当前求出的最大流来得出新的最大流,这样会快一些,不过我不会。。。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 #define INF (1<<30) 6 int n,vs,vt,NV,c[444][444],f[444][444],level[444]; 7 bool bfs(){ 8 memset(level,0,sizeof(level)); 9 bool vis[444]={0}; 10 vis[vs]=1; 11 int que[444],front=0,rear=0; 12 que[rear++]=vs; 13 while(front<rear){ 14 int u=que[front++]; 15 for(int v=1; v<=NV; ++v){ 16 if(vis[v] || c[u][v]==f[u][v]) continue; 17 level[v]=level[u]+1; 18 vis[v]=1; 19 que[rear++]=v; 20 } 21 22 } 23 return vis[vt+n]; 24 } 25 int dfs(int u,int s){ 26 if(u==vt+n) return s; 27 int res=s,tmp; 28 for(int v=1; v<=NV; ++v){ 29 if(level[v]!=level[u]+1 || c[u][v]==f[u][v]) continue; 30 tmp=dfs(v,min(s,c[u][v]-f[u][v])); 31 f[u][v]+=tmp; 32 f[v][u]-=tmp; 33 s-=tmp; 34 } 35 return res-s; 36 } 37 int dinic(){ 38 int res=0; 39 while(bfs()) res+=dfs(vs,INF); 40 return res; 41 } 42 int main(){ 43 int a; 44 scanf("%d%d%d",&n,&vs,&vt); 45 NV=n<<1; 46 for(int i=1;i<=n;++i){ 47 c[i][i+n]=1; 48 for(int j=1;j<=n;++j){ 49 scanf("%d",&a); 50 if(i==j || a==0) continue; 51 c[i+n][j]=INF; 52 } 53 } 54 c[vs][vs+n]=INF; c[vt][vt+n]=INF; 55 if(c[vs+n][vt]){ 56 puts("NO ANSWER!"); 57 return 0; 58 } 59 int ans=dinic(); 60 printf("%d\n",ans); 61 for(int i=1; i<=n&&ans; ++i){ 62 if(i==vs||i==vt || f[i][i+n]==0) continue; 63 memset(f,0,sizeof(f)); 64 c[i][i+n]=0; 65 if(dinic()<ans){ 66 --ans; 67 printf("%d ",i); 68 }else{ 69 c[i][i+n]=1; 70 } 71 } 72 return 0; 73 }