1. 程式人生 > 實用技巧 >《2020/8/1 訓練 - 題解》

《2020/8/1 訓練 - 題解》

Earthquake Damage(TZOJ2619)

題意:給定一張無向圖。

給出一些記號點,這些點沒有被刪去,但是無法直接或者間接到達1號點。

問最少刪去多少個點,使得所有的記號點滿足無法到達1號點。

首先考慮轉化模型,可以看成最小割的思想。

問刪除最少多少的點,使圖不連通,首先,圖不連通的話,不一定就到達不了1號點。

所以要應該改成,最少刪除多少的點,使源點無法匯到匯點。

那麼將源點和所有記號點連邊,如果源點無法到達匯點,那麼就滿足所有和源點相連的記號點都無法到達匯點。(即最小割)

所以建圖思路就很明顯了,記號點和源點,容量為INF。

因為最小割是割邊,所以我們要進行拆點,對於記號點,不能割去,那麼容量設為INF。

對於非記號點,容量設為1即可。中間連邊容量也為INF。

然後因為最後是判斷能不能到1,所以直接將1作為匯點即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef long double ld;
typedef pair<LL,int> pii;
const int N = 2e5+5;
const int M = 1e6+5;
const LL Mod = 1e9+7;
#define rg register
#define pi acos(-1)
#define INF 1e9
#define
INM INT_MIN #define dbg(ax) cout << "now this num is " << ax << endl; inline int read() { int x = 0,f = 1;char c = getchar(); while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();} while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();}
return x*f; } int n,m,s,t,cnt = -1,C; int head[N],dep[N],cur[N],col[N]; struct Node{int to,dis,next;}e[M<<2]; inline void add(int u,int v,int w) { e[++cnt].to = v,e[cnt].dis = w,e[cnt].next = head[u],head[u] = cnt; e[++cnt].to = u,e[cnt].dis = 0,e[cnt].next = head[v],head[v] = cnt; } bool bfs()//分層 { queue<int> Q; memset(dep,-1,sizeof(dep)); dep[s] = 0; Q.push(s); while(!Q.empty()) { int u = Q.front(); Q.pop(); for(int i=head[u];i!=-1;i=e[i].next) { int y = e[i].to,d = e[i].dis; if(dep[y] == -1 && d > 0) { dep[y] = dep[u]+1; Q.push(y); } } } return dep[t] != -1; } int dfs(int u,int flow) { int nowflow = 0,k; if(u == t) return flow; for(int i=head[u];i!=-1;i=e[i].next) { cur[u] = i;//當前弧優化 int y = e[i].to,d = e[i].dis; if((dep[y] == dep[u]+1) && d > 0) { if(k = dfs(y,min(flow-nowflow,d))) { e[i].dis -= k; e[i^1].dis += k; nowflow += k; if(nowflow == flow) break; } } } if(nowflow == 0) dep[u] = -1;//炸點優化 return nowflow; } LL slove() { LL ans = 0; while(bfs()) { for(int i=1;i<=n;++i) cur[i] = head[i]; ans += dfs(s,INF); } return ans; } int main() { //s - 0,i st:[i,n] ed [i+n,n+n]; // n = read(),m = read(),C = read(); t = 1,s = n+n+1; memset(head,-1,sizeof(head)); while(m--) { int u,v;u = read(),v = read(); if(u == v) continue; add(u+n,v,INF); add(v+n,u,INF); } for(int i = 1;i <= C;++i) { int x;x = read(); col[x] = 1; add(s,x,INF); } for(int i = 1;i <= n;++i) { if(col[i] == 1) { add(i,i+n,INF); } else { add(i,i+n,1); } } LL ans = slove(); printf("%lld\n",ans); //system("pause"); return 0; }
View Code