51nod1299 监狱逃离 最小割
Description
監(jiān)獄有N條道路連接N + 1個(gè)交點(diǎn),編號(hào)0至N,整個(gè)監(jiān)獄被這些道路連在一起(任何2點(diǎn)之間都有道路),人們通過(guò)道路在交點(diǎn)之間走來(lái)走去。其中的一些交點(diǎn)只有一條路連接,這些點(diǎn)是監(jiān)獄的出口。在各個(gè)交點(diǎn)中有M個(gè)點(diǎn)住著犯人(M <= N + 1),剩下的點(diǎn)可以安排警衛(wèi),有警衛(wèi)把守的地方犯人無(wú)法通過(guò)。給出整個(gè)監(jiān)獄的道路情況,以及犯人所在的位置,問(wèn)至少需要安排多少個(gè)警衛(wèi),才能保證沒(méi)有1個(gè)犯人能夠逃到出口,如果總有犯人能夠逃出去,輸出-1。
如上圖所示,點(diǎn)1,6 住著犯人,0,4,5,7,8是出口,至少需要安排4個(gè)警衛(wèi)。
Input
第1行:2個(gè)數(shù)N, M中間用空格分隔,N表示道路的數(shù)量,M表示犯人的數(shù)量(1<= N <= 100000, 0 <= M <= N + 1)。
之后N行:每行2個(gè)數(shù)S, E中間用空格分隔,表示點(diǎn)編號(hào)為S的點(diǎn)同編號(hào)為E的點(diǎn)之間有道路相連。(0 <= S, E <= N)。
之后的M行,每行1個(gè)數(shù)Pi,表示編號(hào)為Pi的點(diǎn)上有犯人。
Output
輸出1個(gè)數(shù)對(duì)應(yīng)最少需要多少警衛(wèi)才能不讓犯人逃出監(jiān)獄。
Solution
一開(kāi)始想的是樹(shù)形dp,后來(lái)發(fā)現(xiàn)最小割好寫(xiě)些
考慮網(wǎng)絡(luò)流最小割。注意到我們要去掉一些點(diǎn)使得有罪犯的點(diǎn)與葉節(jié)點(diǎn)不連通,所以拆罪犯x和x’連1的邊
對(duì)于原圖中的一條邊(x,y)連(x’,y)和(y’-x)容量為∞
對(duì)于罪犯x連(st,x’)容量為∞表示x不能放
對(duì)于葉子x連(x’,ed)容量為∞
對(duì)于每一個(gè)點(diǎn)向源點(diǎn)匯點(diǎn)連邊容量為∞
很神奇,n巨大也能用dinic,不知不加當(dāng)前弧能不能過(guò)
Code
#include <stdio.h> #include <string.h> #include <queue> #define rep(i,st,ed) for (int i=st;i<=ed;++i) #define fill(x,t) memset(x,t,sizeof(x)) #define min(x,y) ((x)<(y)?(x):(y)) #define INF 0x3f3f3f3f #define N 400005 #define E N<<3|1 std:: queue<int>que; struct edge{int x,y,w,next;}e[E]; int dis[N],d[N]; int cur[N],ls[N],edCnt=1; int n,m; void addEdge(int x,int y,int w) {e[++edCnt]=(edge){x,y,w,ls[x]}; ls[x]=edCnt;e[++edCnt]=(edge){y,x,0,ls[y]}; ls[y]=edCnt; } int bfs(int st,int ed) {while (!que.empty()) que.pop();fill(dis,-1);dis[st]=0;que.push(st);while (!que.empty()) {int now=que.front(); que.pop();for (int i=ls[now];i;i=e[i].next) {if (e[i].w>0&&dis[e[i].y]==-1) {dis[e[i].y]=dis[now]+1;que.push(e[i].y);if (e[i].y==ed) return 1;}}}return 0; } int find(int now,int ed,int mn) {if (now==ed||!mn) return mn;int ret=0;for (int &i=cur[now];i;i=e[i].next) {if (e[i].w>0&&dis[now]+1==dis[e[i].y]) {int tmp=find(e[i].y,ed,min(e[i].w,mn-ret));e[i].w-=tmp;e[i^1].w+=tmp;ret+=tmp;if (ret==mn) break;}}return ret; } int main(void) {scanf("%d%d",&n,&m); ++n;int ST=0,ED=n*2+1;rep(i,2,n) {int x,y;scanf("%d%d",&x,&y); ++x; ++y;addEdge(x+n,y,INF);addEdge(y+n,x,INF);++d[x]; ++d[y];}rep(i,1,m) {int x;scanf("%d",&x); ++x;addEdge(ST,x+n,INF);}rep(i,1,n) addEdge(i,i+n,1);rep(i,1,n) if (d[i]==1) addEdge(i+n,ED,INF);int ans=0;while (bfs(ST,ED)) {rep(i,0,ED) cur[i]=ls[i];ans+=find(ST,ED,INF);}printf("%d\n",ans);return 0; }
總結(jié)
以上是生活随笔為你收集整理的51nod1299 监狱逃离 最小割的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 【51nod1299】监狱逃离(树形DP
- 下一篇: [51nod1299] 监狱逃离(最小点