[关闭]
@ysner 2018-08-06T13:20:07.000000Z 字数 2757 阅读 1630

[luoguP4142]洞穴遇险

网络流


题面

戳我

解析

这种用来拼接的奇形怪状的东西,要不就是轮廓线,要不就是网络流。

为了表示奇数点(即)的危险值,把该点拆为两个点,连一条边长为该点危险值相反数的边(两点分别称为起点和终点)。

鉴于一根柱子跨越个格子,其中一点为奇数点,另外两个点都是偶数点,不能区分。

于是也要把偶数点分为两类(不用拆点)。一类连源点,一类连汇点。连汇点的一类连奇数点的起点,另一类连终点。(让源点出发能到汇点就成)

然后思考如何表示柱子。

如果强行给柱子规定方向,则有个方向。
表示出来,有两种情况,一是轴方向出,轴方向进;另一种是轴方向进,轴方向出。
于是两个奇数点分别反映一种情况,同时注意相邻的偶数点连奇数点中的起点、还是终点即可。

还要注意的是,最小费用最大流模板求出的是在最大流前提下的最小流,在后期,可能为了得到最大流而付出更多费用(在本题中就是为了放更多柱子而增加不稳定度)。在费用开始非负时(开始退流时)记得

唯一一种能让网络流TLE的方式就是cnt=0

  1. // luogu-judger-enable-o2
  2. #include<iostream>
  3. #include<cstdio>
  4. #include<cstdlib>
  5. #include<cstring>
  6. #include<cmath>
  7. #include<algorithm>
  8. #include<vector>
  9. #include<queue>
  10. #define re register
  11. #define il inline
  12. #define ll long long
  13. #define max(a,b) ((a)>(b)?(a):(b))
  14. #define min(a,b) ((a)<(b)?(a):(b))
  15. #define fp(i,a,b) for(re int i=a;i<=b;i++)
  16. #define fq(i,a,b) for(re int i=a;i>=b;i--)
  17. using namespace std;
  18. const int mod=1e9+7,N=5e3+100;
  19. struct Edge{int to,nxt,w,c;}e[N*10];
  20. int n,m,k,s,sum,h[N],d[55][55],ans=0,dis[N],S,T,pe[N],pv[N],tot,cnt=1,g;
  21. bool vis[N],ban[55][55];
  22. il void add(re int u,re int v,re int w,re int c)
  23. {
  24. if(u==-1||v==-1) return ;
  25. e[++cnt]=(Edge){v,h[u],w,c};h[u]=cnt;
  26. e[++cnt]=(Edge){u,h[v],0,-c};h[v]=cnt;
  27. }
  28. queue<int>Q;
  29. il ll gi()
  30. {
  31. re ll x=0,t=1;
  32. re char ch=getchar();
  33. while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
  34. if(ch=='-') t=-1,ch=getchar();
  35. while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
  36. return x*t;
  37. }
  38. il int id(re int x,re int y){return (x-1)*n+y;}
  39. il int SPFA()
  40. {
  41. memset(dis,63,sizeof(dis));dis[S]=0;vis[S]=1;Q.push(S);
  42. while(!Q.empty())
  43. {
  44. re int u=Q.front();Q.pop();
  45. for(re int i=h[u];i+1;i=e[i].nxt)
  46. {
  47. re int v=e[i].to;//printf("!!!%d %d\n",u,v);
  48. if(dis[v]>dis[u]+e[i].c&&e[i].w)
  49. {
  50. dis[v]=dis[u]+e[i].c;
  51. pe[v]=i;pv[v]=u;
  52. if(!vis[v]) vis[v]=1,Q.push(v);
  53. }
  54. }
  55. vis[u]=0;
  56. }
  57. return dis[T]<dis[0];
  58. }
  59. int main()
  60. {
  61. //freopen("marshland.in","r",stdin);
  62. //freopen("marshland.out","w",stdout);
  63. memset(h,-1,sizeof(h));
  64. n=gi();m=gi();k=gi();g=n*n;S=2*g+1;T=2*g+2;
  65. fp(i,1,n)
  66. fp(j,1,n)
  67. d[i][j]=gi(),s+=d[i][j];
  68. fp(i,1,k)
  69. {
  70. re int u=gi(),v=gi();
  71. ban[u][v]=1;
  72. }
  73. fp(i,1,n)
  74. fp(j,1,n)
  75. {
  76. if(ban[i][j]) continue;
  77. if((i+j)%2) add(id(i,j),id(i,j)+g,1,-d[i][j]);
  78. if((i+j)%2&&j%2==0)
  79. {
  80. if(i>1&&!ban[i-1][j]) add(id(i,j)+g,id(i-1,j),1,0);
  81. if(i<n&&!ban[i+1][j]) add(id(i,j)+g,id(i+1,j),1,0);
  82. if(j>1&&!ban[i][j-1]) add(id(i,j-1),id(i,j),1,0);
  83. if(j<n&&!ban[i][j+1]) add(id(i,j+1),id(i,j),1,0);
  84. }
  85. if((i+j)%2&&j%2==1)
  86. {
  87. if(i>1&&!ban[i-1][j]) add(id(i-1,j),id(i,j),1,0);
  88. if(i<n&&!ban[i+1][j]) add(id(i+1,j),id(i,j),1,0);
  89. if(j>1&&!ban[i][j-1]) add(id(i,j)+g,id(i,j-1),1,0);
  90. if(j<n&&!ban[i][j+1]) add(id(i,j)+g,id(i,j+1),1,0);
  91. }
  92. if((i+j)%2==0&&j%2==1) add(S,id(i,j),1,0);
  93. if((i+j)%2==0&&j%2==0) add(id(i,j),T,1,0);
  94. }
  95. while(SPFA()&&m)
  96. {
  97. if(dis[T]>=0) break;
  98. sum=2e9;
  99. for(re int i=T;i!=S;i=pv[i])
  100. sum=min(sum,e[pe[i]].w);m-=sum;//printf("%d\n",sum);
  101. for(re int i=T;i!=S;i=pv[i])
  102. e[pe[i]].w-=sum,e[pe[i]^1].w+=sum,ans+=sum*e[pe[i]].c;
  103. }
  104. printf("%d\n",s+ans);
  105. fclose(stdin);
  106. fclose(stdout);
  107. return 0;
  108. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注