EZOJ 宝石迷阵 建图+网络流匹配

Posted alan-luo

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了EZOJ 宝石迷阵 建图+网络流匹配相关的知识,希望对你有一定的参考价值。

题面:

  封印恶魔的地方可以看作是一个 n*m 的矩形,包含了 n*m 个祭坛,并且其 中有一些祭坛已经损坏了。

  如果 i+j 为偶数,那么第 i 行第 j 列的祭坛只要没有损坏,就一定会封印有一个恶魔。

   其他的没有损坏的祭坛可以用来放置魔法水晶,但是一个祭坛上只能放置一 个魔法水晶,并且一个魔法水晶只能向一个与它相邻的祭坛输送魔力,从而加固 封印。

   对于一个恶魔来说,如果与它相邻的两个成直角的水晶同时向它所在的祭坛 输送魔力的话,它就会被再次封印。 现在 Z 君想知道他最多可以封印多少恶魔?

 

分析:

  这道题一眼看上去比较乱,但是其中的关系却很简单。

  若格子没有损坏,i+j为偶数则为恶魔,否则为魔法水晶,两个魔法水晶与一个恶魔相邻且成直角,就可以选择一起封印他。

  我们仔细一想:什么叫成直角!?!?说的那么文艺,实际上就是与同一个恶魔相邻的位于奇数列和偶数列的两个魔法水晶!

  那不就好办了?我们将奇数列和偶数列的魔法水晶分开来考虑,将恶魔拆成两个点,就形成了“一个人喜欢两类物品中的各一种,只能各选一种,问最多几人满意”这样的问题,于是就和我们上一篇中讨论的问题一样的了,拆点、连边、最大流、结束!

代码:(我不知道为啥别人都写了一百大几十行……)

技术分享图片
 1 #include<bits/stdc++.h>
 2 #define ms(a,x) memset(a,x,sizeof(a))
 3 using namespace std;int tot=0;
 4 const int N=10005,inf=0x3f3f3f3f;
 5 int S,T,q[N],h[N],c=1,n,m,k,d[N],cnt=0;
 6 int c1[55][55][2],fx[4]={1,0,-1,0};
 7 struct node{int y,z,nxt;}e[N*2];
 8 int fy[4]={0,1,0,-1};char s[55];
 9 bool isb(int i,int j){
10     return c1[i][j][0]!=0;
11 } bool isn(int i,int j){
12     return ((i+j)&1);
13 } void add(int x,int y,int z){
14     e[++c]=(node){y,z,h[x]};h[x]=c;
15     e[++c]=(node){x,0,h[y]};h[y]=c;
16 } bool bfs(){
17     int f=1,t=0;ms(d,-1);
18     q[++t]=S;d[S]=0;
19     while(f<=t){
20         int x=q[f++];
21         for(int i=h[x],y;i;i=e[i].nxt)
22         if(d[y=e[i].y]==-1&&e[i].z)
23         d[y]=d[x]+1,q[++t]=y;
24     } return (d[T]!=-1);
25 } int dfs(int x,int f){
26     if(x==T) return f;int w,tmp=0;
27     for(int i=h[x],y;i;i=e[i].nxt)
28     if(d[y=e[i].y]==d[x]+1&&e[i].z){
29         w=dfs(y,min(e[i].z,f-tmp));
30         if(!w) d[y]=-1;
31         e[i].z-=w;e[i^1].z+=w;
32         tmp+=w;if(tmp==f) return f;
33     } return tmp;
34 } void dinic(){
35     while(bfs()) tot+=dfs(S,inf);
36 } int main(){
37     scanf("%d%d",&n,&m);S=0;
38     for(int i=1;i<=n;i++){
39         scanf("%s",s+1);
40         for(int j=1;j<=m;j++){
41             if(s[j]==X) continue;
42             c1[i][j][0]=++cnt;
43             if(!isn(i,j)) c1[i][j][1]=++cnt,
44             add(c1[i][j][0],c1[i][j][1],1);
45         }
46     } T=++cnt;
47     for(int i=1;i<=n;i++)
48     for(int j=1;j<=m;j++){
49         if(!isb(i,j)) continue;
50         if(isn(i,j))
51         for(int v=0;v<4;v++){
52             int x=i+fx[v],y=j+fy[v];
53             if(!isb(x,y)) continue;
54             if(j&1) 
55             add(c1[i][j][0],c1[x][y][0],1);
56             else
57             add(c1[x][y][1],c1[i][j][0],1);
58         } if(isn(i,j)){
59             if(j&1) add(S,c1[i][j][0],1);
60             else add(c1[i][j][0],T,1);
61         }
62     } dinic();
63     printf("%d
",tot);
64     return 0;
65 }
拆点最大流

 

以上是关于EZOJ 宝石迷阵 建图+网络流匹配的主要内容,如果未能解决你的问题,请参考以下文章

hdu5249 Tricks Device(网络流最大匹配)

培训补坑(day4:网络流建模与二分图匹配)

带有红宝石集合/可枚举的酷技巧和富有表现力的片段[关闭]

巨坑网络流线性规划与网络流24题

网络流24题小结

网络流建图/模型总结