hdu 3987 Harry Potter and the Forbidden Forest
来源:互联网 发布:停用移动数据怎么关闭 编辑:程序博客网 时间:2024/05/22 12:04
最小割:我用的比较传统的方法,因为最小割=最大流,所以可以先用sap预处理一下图,找出满流的边,在把这下满流的边的权值更改为1,其余的变成inf,再跑一遍sap即可得到答案。#include<stdio.h>#include<string.h>#include<iostream>using namespace std;const int N=2010;const int M=550000;const int inf=(1<<28);int head[N];int cnt,n,s,T,t,e,cas,m,u,v,c,d;struct Edge{ int v,c,next;}edge[M];void add_edge(int u,int v,int c) { edge[e].v=v; edge[e].c=c; edge[e].next=head[u]; head[u]=e++; edge[e].v=u; edge[e].c=0; edge[e].next=head[v]; head[v]=e++; } int sap(){ int pre[N],cur[N],dis[N],gap[N]; int flow=0,aug=inf,u; bool flag; for(int i=0; i<n; i++) { cur[i]=head[i]; gap[i]=dis[i]=0; } gap[s]=n;//dis为0的有n个 u=pre[s]=s; while(dis[s]<n) { flag=0; for(int &j=cur[u]; j!=-1; j=edge[j].next) { int v=edge[j].v; if(edge[j].c>0&&dis[u]==dis[v]+1) { flag=1; if(edge[j].c<aug) aug=edge[j].c; pre[v]=u; u=v; if(u==t) { flow+=aug; while(u!=s) { u=pre[u]; edge[cur[u]].c-=aug; edge[cur[u]^1].c+=aug; } aug=inf; } break; } } if(flag) continue; int mindis=n; for(int j=head[u]; j!=-1; j=edge[j].next) { int v=edge[j].v; if(edge[j].c>0&&dis[v]<mindis) { mindis=dis[v]; cur[u]=j; } } if((--gap[dis[u]])==0) break; gap[dis[u]=mindis+1]++; u=pre[u]; } return flow;}int main(){ cas=0; scanf("%d",&T); while(T--) { cas++; scanf("%d%d",&n,&m); e=0;s=0;t=n-1; memset(head,-1,sizeof(head)); for(int i=0;i<m;i++) { scanf("%d%d%d%d",&u,&v,&c,&d); if(d) add_edge(v,u,c); add_edge(u,v,c); } int pp = sap(); for(int i=0;i<e;i++) { if(i&1) edge[i].c=0; else { if(edge[i].c==0){ edge[i].c=1; edge[i^1].c=0; } else { edge[i].c=inf; edge[i^1].c=0; } } } int answer=sap(); printf("Case %d: %d\n",cas,answer); } return 0;}