【bzoj1143】[CTSC2008]祭祀river

来源:互联网 发布:painter是什么软件 编辑:程序博客网 时间:2024/05/04 04:43

在一次noip模拟赛,我的存边方法由于边界原因并不是正确的,然后就没有拿到AC,结果我想了想,想到了一个笑话,我写了2年的网络流的存边都是那样存的

http://www.lydsy.com/JudgeOnline/problem.php?id=1143

Dilworth定理:最小链覆盖数 = 最长反链长度
其对偶定理:最长链长度 = 最小反链覆盖数
然后我们发现水流不能从一个祭祀点流到另一个祭祀点,其实意思就是祭祀点组成了一条反链
也就是说我们要求的是最长反链
也就是最小链覆盖
在这里要注意,最小链覆盖≠最小路径覆盖
为什么不等于呢,因为链可以不是连续的一条路径
所以我们要先跑一遍Floyd,把间接到达的点改为直接到达,这样就可以跑最小路径覆盖了
(只记得结论不知道链是什么意思WA了两发qwq
顺便改了改自己网络流模板,然后就写错了一个小地方,还是不够熟悉啊……
AC code:
#include <cstdio>#include <vector>using namespace std;vector<int> g[250];struct edge{int u,v,cap,flow;} a[250050];int tot,n,i,num[250],p[250],d[250],cur[250],m,M[250][250],j,k;void link(int x,int y){a[tot].u=x;a[tot].v=y;a[tot].cap=1;a[tot].flow=0;g[x].push_back(tot++);a[tot].u=y;a[tot].v=x;a[tot].cap=0;a[tot].flow=0;g[y].push_back(tot++);}int maxflow(int s,int t){num[0]=(n << 1)+2;int x=s,ans=0;while (d[s]<((n << 1)+2)){if (x==t){ans++;while (x!=s){a[p[x]].flow++;a[p[x]^1].flow--;x=a[p[x]].u;}}bool zw=true;for (i=cur[x];i<g[x].size();i++) if (a[g[x][i]].cap>a[g[x][i]].flow && d[a[g[x][i]].v]+1==d[x]){cur[x]=i;p[a[g[x][i]].v]=g[x][i];x=a[g[x][i]].v;zw=false;break;}if (zw){if (--num[d[x]]==0) return ans;d[x]=(n << 1)+2;cur[x]=0;for (i=cur[x];i<g[x].size();i++) if (a[g[x][i]].cap>a[g[x][i]].flow) d[x]=min(d[x],d[a[g[x][i]].v]+1);num[d[x]]++;if (x!=s) x=a[p[x]].u;}}return ans;}int main(){scanf("%d%d",&n,&m);for (i=1;i<=m;i++){int x,y;scanf("%d%d",&x,&y);M[x][y]=1;}for (k=1;k<=n;k++)for (i=1;i<=n;i++)for (j=1;j<=n;j++) if (i!=j && j!=k && k!=i && M[i][k] && M[k][j] && !(M[i][j])) M[i][j]=1;for (i=1;i<=n;i++)for (j=1;j<=n;j++) if (M[i][j]) link(i,j+n);for (i=1;i<=n;i++){link(n << 1|1,i);link(i+n,(n << 1)+2);}printf("%d\n",n-maxflow(n << 1|1,(n << 1)+2));return 0;}

1 0
原创粉丝点击