码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2019-01-09 11:20:14      阅读:172      评论:0      收藏:0      [点我收藏+]

标签:个人   continue   code   char   lse   ons   void   spl   isp   

题面:

  封印恶魔的地方可以看作是一个 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\n",tot);
64     return 0;
65 }
拆点最大流

 

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

标签:个人   continue   code   char   lse   ons   void   spl   isp   

原文地址:https://www.cnblogs.com/Alan-Luo/p/10242465.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!