1. 程式人生 > >EZOJ 寶石迷陣 建圖+網絡流匹配

EZOJ 寶石迷陣 建圖+網絡流匹配

bsp 代碼 一個 拆點 esp fin sin div str

題面:

  封印惡魔的地方可以看作是一個 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 寶石迷陣 建圖+網絡流匹配