当前位置: 代码迷 >> 综合 >> bzoj 1797: [Ahoi2009]Mincut 最小割
  详细解决方案

bzoj 1797: [Ahoi2009]Mincut 最小割

热度:22   发布时间:2023-10-29 13:35:37.0

是又是一道好题啊!

首先,我觉得可以很容易可以想到一个O(m?)的复杂度,但对于这一题,每条边都跑一次肯定是不现实的做法。。
然后我就不会了

于是去看题解。。发现居然有结论。。
我就把结论总结一下吧

结论1(用于解决第一问):

对于一条边,要是有一种割集包含他的话,那么他肯定是满流的。但如果他是漫流的,不一定有一个割集包含他。

证明:
我们先证明:如果一条边不是满流的,那么肯定没有割集包含他。这个的话应该挺好懂的,假如他没有满流,那么肯定是后面有一条或若干条边限制了他,那么我们只需要割掉限制他的东西,并不需要割掉它。。
由此得出,第一句话是对的
第二句我们可以举反例,这个随手画画就好了。。

但这一个结论并不可以解决第一问,我们还需要第二个

结论2(用于解决第一问):

如果一条边的两端x和y,在残余网络中属于同一个连通分量,那么也没有一个割集包含他

证明:
这个也很容易啊!这不就说明后面还是有东西在限制他嘛。。

于是第一问就解决了。。

结论3(用于解决第二问):

满流的桥是一定要割的。。

证明:不用了吧

于是这题就做完了

#include<cstdio>
#include<queue>
#include<algorithm>
#include<cstring>
#include<iostream>
using namespace std;
const int N=4005;
const int M=60005*2;
struct qq
{int x,y,z,last;
}s[M];int num,last[N];
int n,m,S,T;
void init (int x,int y,int z)
{num++;s[num].x=x;s[num].y=y;s[num].z=z;s[num].last=last[x];last[x]=num;
}
int h[N];
bool bt ()
{memset(h,-1,sizeof(h));h[S]=1;queue<int> q;q.push(S);while (!q.empty()){int x=q.front();q.pop();for (int u=last[x];u!=-1;u=s[u].last){int y=s[u].y;if (s[u].z>0&&h[y]==-1){h[y]=h[x]+1;q.push(y);}}}return h[T]!=-1;
}
int mymin (int x,int y){
   return x<y?x:y;}
int dfs (int x,int f)
{if (x==T) return f;int s1=0;for (int u=last[x];u!=-1;u=s[u].last){int y=s[u].y;if (s[u].z>0&&h[y]==h[x]+1&&s1<f){int lalal=dfs(y,mymin(s[u].z,f-s1));s1+=lalal;s[u].z-=lalal;s[u^1].z+=lalal;}}if (s1==0) h[x]=-1;return s1;
}
int dfn[N],low[N],belong[N],cnt,sta[N],lalal,shen;
bool in[N];
void dfs1 (int x)
{dfn[x]=low[x]=++lalal;sta[++cnt]=x;in[x]=true;for (int u=last[x];u!=-1;u=s[u].last){if (s[u].z>0){int y=s[u].y;if (dfn[y]==-1){dfs1(y);low[x]=mymin(low[x],low[y]);}else if (in[y]) low[x]=mymin(dfn[y],low[x]);}}if (low[x]==dfn[x]){shen++;int now;do{now=sta[cnt--];belong[now]=shen;in[now]=false;}while (now!=x);}
}
int main()
{num=1;memset(last,-1,sizeof(last));scanf("%d%d%d%d",&n,&m,&S,&T);for (int u=1;u<=m;u++){int x,y,z;scanf("%d%d%d",&x,&y,&z);init(x,y,z);init(y,x,0);}int ans=0;while (bt()) ans=ans+dfs(S,1<<30);shen=lalal=cnt=0;memset(dfn,-1,sizeof(dfn));memset(in,false,sizeof(in));for (int u=1;u<=n;u++)if (dfn[u]==-1)dfs1(u);//for (int u=1;u<=n;u++) printf("%d ",belong[u]);for (int u=2;u<=m*2;u+=2){if (s[u].z!=0) printf("0 0\n");else{if (belong[s[u].x]!=belong[s[u].y]) printf("1 ");else printf("0 ");if ((belong[s[u].x]==belong[S])&&(belong[s[u].y]==belong[T])) printf("1\n");else printf("0\n");}}return 0;
}