生活随笔
收集整理的這篇文章主要介紹了
[清华集训2017]无限之环(网络流)
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
很妙的一道題
對(duì)于每個(gè)格子,它合法與否,只跟它上下左右的相鄰格子有關(guān),所以可以想到黑白染色
(用 (i,j) 表示 i 行 j 列的格子,我把 (i+j) %2 == 0 的格子染成白色,把(i+j)%2 == 1 的格子染成黑色)
關(guān)鍵是怎么描述旋轉(zhuǎn)操作
我樸實(shí)的想法是給每個(gè)格子建四個(gè)點(diǎn),每個(gè)點(diǎn)代表格子可通過(guò)旋轉(zhuǎn)達(dá)到的一種狀態(tài),從格子的初始狀態(tài)向格子其它狀態(tài)連邊,然后把格子間可以匹配的狀態(tài)連起來(lái),再然后……就沒(méi)有然后了
看了題解,真的被驚到了
還是把每個(gè)格子拆成4個(gè)節(jié)點(diǎn),對(duì)應(yīng)四個(gè)方向上的接口
從源點(diǎn)向白格的接口連流量上界1,費(fèi)用0的邊
從黑格的接口向匯點(diǎn)連流量上界1,費(fèi)用0的邊
從黑格的接口向可以匹配的白格的接口連流量上界1,費(fèi)用0的邊
然后旋轉(zhuǎn)操作,就可以通過(guò)一種神奇方式描述出來(lái):
AD O BC
把這個(gè)看成一個(gè)白格(黑格類似,只是連邊方向相反)
邊(u->v,f,w)代表從 u 到 v,流量上界 f,費(fèi)用 w 的邊
下文描述的旋轉(zhuǎn)方向均為順時(shí)針
1.此格有1個(gè)接口:
A
|
D O BC
(A->B ,1,1)) 對(duì)應(yīng)轉(zhuǎn)90度
(A->C, 1,2)) 對(duì)應(yīng)轉(zhuǎn)180度
(A->D ,1,1)) 對(duì)應(yīng)轉(zhuǎn)270度
2.此格有2個(gè)接口:
情況1:
A
|
D O —— BC
(A->C, 1,1)) 對(duì)應(yīng)轉(zhuǎn)90度
(B->D ,1,1)) 對(duì)應(yīng)轉(zhuǎn)270度
(A->C, 1,1))+(B->D ,1,1)) 對(duì)應(yīng)轉(zhuǎn)180度
情況2:
A
|
D O B
|C
不能轉(zhuǎn),忽略
3.此格有3個(gè)接口:
A
|
D O —— B
|C
(A->D ,1,1)) 對(duì)應(yīng)轉(zhuǎn)270度
(B->D, 1,2)) 對(duì)應(yīng)轉(zhuǎn)180度
(C->D ,1,1)) 對(duì)應(yīng)轉(zhuǎn)90度
4.此格有4個(gè)接口:
A
|
D —— O —— B
|C
轉(zhuǎn)了也沒(méi)區(qū)別,忽略
建完圖后跑最小費(fèi)用最大流即可
如果我表達(dá)不清的話,這是樣例1的建圖,很丑,湊合著看吧
圖上標(biāo)的數(shù)代表費(fèi)用,沒(méi)標(biāo)的邊默認(rèn)費(fèi)用為0,所有邊的流量上界默認(rèn)為1
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std
;
const int inf
=0x7fffffff;
const int N
=8100;
const int M
=200010;
struct Edge
{int u
,v
,f
,w
,nxt
;
}edge
[M
<<1];
int s
,t
,head
[N
],cnt
,maxflow
,mincost
,dis
[N
],inque
[N
],pre
[N
];
queue
<int> q
;
int n
,m
,id
[2005][2005][4],num
,gr
[2005][2005],tot
;
void add(int u
,int v
,int f
,int w
){edge
[cnt
].u
=u
;edge
[cnt
].v
=v
;edge
[cnt
].f
=f
;edge
[cnt
].w
=w
;edge
[cnt
].nxt
=head
[u
];head
[u
]=cnt
++;edge
[cnt
].u
=v
;edge
[cnt
].v
=u
;edge
[cnt
].f
=0;edge
[cnt
].w
=-w
;edge
[cnt
].nxt
=head
[v
];head
[v
]=cnt
++;
}
bool spfa(){memset(dis
,0x7f,sizeof(dis
));memset(inque
,0,sizeof(inque
));memset(pre
,-1,sizeof(pre
));dis
[s
]=0;q
.push(s
);inque
[s
]=1;while(!q
.empty()){int u
=q
.front();q
.pop();inque
[u
]=0;for(int i
=head
[u
];i
!=-1;i
=edge
[i
].nxt
){int v
=edge
[i
].v
;if(edge
[i
].f
>0&&dis
[v
]>dis
[u
]+edge
[i
].w
){dis
[v
]=dis
[u
]+edge
[i
].w
;pre
[v
]=i
;if(!inque
[v
]){q
.push(v
);inque
[v
]=1;}}}} if(pre
[t
]!=-1) return 1;return 0;
}
void EK(){int flow
;while(spfa()){flow
=inf
;int x
=pre
[t
];while(x
!=-1){flow
=min(edge
[x
].f
,flow
);x
=pre
[edge
[x
].u
];}x
=pre
[t
];while(x
!=-1){edge
[x
].f
-=flow
;edge
[x
^1].f
+=flow
;mincost
+=flow
*edge
[x
].w
;x
=pre
[edge
[x
].u
];}maxflow
+=flow
;}
}
int main(){memset(head
,-1,sizeof(head
));scanf("%d%d",&n
,&m
);for(int i
=1;i
<=n
;i
++)for(int j
=1;j
<=m
;j
++)for(int k
=0;k
<4;k
++)id
[i
][j
][k
]=++num
;s
=++num
,t
=++num
; for(int i
=1;i
<=n
;i
++){for(int j
=1;j
<=m
;j
++){scanf("%d",&gr
[i
][j
]);int tt
=0,pos
[5]={-1,-1,-1,-1,-1},npos
=-1;for(int k
=0;k
<4;k
++){if(gr
[i
][j
]&(1<<k
)){tot
++;pos
[++tt
]=k
;if((i
+j
)%2==0) add(s
,id
[i
][j
][k
],1,0);else add(id
[i
][j
][k
],t
,1,0);}else npos
=k
;}if(tt
==1){if((i
+j
)%2==0){add(id
[i
][j
][pos
[1]],id
[i
][j
][(pos
[1]+1)%4],1,1);add(id
[i
][j
][pos
[1]],id
[i
][j
][(pos
[1]+2)%4],1,2);add(id
[i
][j
][pos
[1]],id
[i
][j
][(pos
[1]+3)%4],1,1);}else{add(id
[i
][j
][(pos
[1]+1)%4],id
[i
][j
][pos
[1]],1,1);add(id
[i
][j
][(pos
[1]+2)%4],id
[i
][j
][pos
[1]],1,2);add(id
[i
][j
][(pos
[1]+3)%4],id
[i
][j
][pos
[1]],1,1);}}else if(tt
==2){if(pos
[2]-pos
[1]==2) continue;if((i
+j
)%2==0){add(id
[i
][j
][pos
[1]],id
[i
][j
][(pos
[1]+2)%4],1,1);add(id
[i
][j
][pos
[2]],id
[i
][j
][(pos
[2]+2)%4],1,1);}else{add(id
[i
][j
][(pos
[1]+2)%4],id
[i
][j
][pos
[1]],1,1);add(id
[i
][j
][(pos
[2]+2)%4],id
[i
][j
][pos
[2]],1,1);}}else if(tt
==3){if((i
+j
)%2==0){add(id
[i
][j
][(npos
+1)%4],id
[i
][j
][npos
],1,1);add(id
[i
][j
][(npos
+2)%4],id
[i
][j
][npos
],1,2);add(id
[i
][j
][(npos
+3)%4],id
[i
][j
][npos
],1,1);}else{add(id
[i
][j
][npos
],id
[i
][j
][(npos
+1)%4],1,1);add(id
[i
][j
][npos
],id
[i
][j
][(npos
+2)%4],1,2);add(id
[i
][j
][npos
],id
[i
][j
][(npos
+3)%4],1,1);}}else continue;}}int dx
[]={-1,0,1,0};int dy
[]={0,1,0,-1};for(int i
=1;i
<=n
;i
++){for(int j
=1;j
<=m
;j
++){if((i
+j
)%2==0){for(int k
=0;k
<=3;k
++){int x
=i
+dx
[k
],y
=j
+dy
[k
];if(x
<1||x
>n
||y
<1||y
>m
) continue;add(id
[i
][j
][k
],id
[x
][y
][(k
+2)%4],1,0);}}}}EK();if(tot
%2!=0||maxflow
!=tot
/2) printf("-1\n"); else printf("%d\n",mincost
);return 0;
}
總結(jié)
以上是生活随笔為你收集整理的[清华集训2017]无限之环(网络流)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。