2020/10/11
阿新 • • 發佈:2020-10-12
kuangbin網路流4題
///連結:https://vjudge.net/problem/UVA-10480 /*題意: n個結點,m路徑,現在讓s和t號結點不要連線,破壞一條點的花費為k。 題解:最小割。但是注意此題有個區別,他是破壞點,所以我們應該拆點,然後在跑。 */ #include"stdio.h" #include"string.h" #include"stack" #include"map" #include"math.h" #include"iostream" #include"string" #include"vector" #include"queue" #include"algorithm" using namespace std; #define OK printf("\n"); #define Debug printf("this_ok\n"); #define INF 1e18 typedef long long ll; #define scanll(a,b) scanf("%lld%lld",&a,&b); #define scanl(a) scanf("%lld",&a); #define printl(a,b) if(b == 0) printf("%lld ",a); else printf("%lld\n",a); #define print_int(a,b) if(b == 0) printf("%d ",a); else printf("%d\n",a); typedef pair<int,int> PII; inline int read(){ int s = 0, w = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') w = -1; ch = getchar(); } while(ch >= '0' && ch <= '9') { s = (s << 3) + (s << 1) + (ch ^ 48); ch = getchar(); } return s * w; } const ll mod = 998244353; const int N = 200000,M = 800000; const double pi = acos(-1); const int inf = 1 << 29; const int dirx[4] = {-1,0,1,0}; const int diry[4] = {0,1,0,-1}; int n,m,t,s,tot; ll maxflow,sum; int head[N],ver[M],Next[M],edge[M],d[N]; int w[N]; queue<int> q; map<string,int> Q; void add(int x,int y,int z){ ver[++ tot] = y; Next[tot] = head[x]; edge[tot] = z; head[x] = tot; ver[++ tot] = x; edge[tot] = 0; Next[tot] = head[y]; head[y] = tot; } void add1(int x,int y,int z){ ver[++ tot] = y; Next[tot] = head[x]; edge[tot] = z; head[x] = tot; ver[++ tot] = x; edge[tot] = 0; Next[tot] = head[y]; head[y] = tot; } bool bfs(){ memset(d,0,sizeof(d)); while(q.size())q.pop(); q.push(s); d[s] = 1; while(q.size()){ int x = q.front(); q.pop(); for(int i = head[x]; i; i = Next[i]) if(edge[i] && !d[ver[i]]){ q.push(ver[i]); d[ver[i]] = d[x] + 1; if(ver[i] == t) return 1; } } return 0; } int dinic(int x,ll flow){ if(x == t) return flow; ll rest = flow,k; for(int i = head[x]; i && rest; i = Next[i]){ if(edge[i] && d[ver[i]] == d[x] + 1){ k = dinic(ver[i],min(rest,(ll)edge[i])); if(!k) d[ver[i]] = 0; edge[i] -= k; edge[i ^ 1] += k; rest -= k; } } return flow - rest; } int main(){ while(~scanf("%d",&n)){ m = read(); for(int i = 0; i <= n + n + 2; i ++) head[i] = 0; tot = 1;s = read(); t = read();t += n; for(int i = 1; i <= n; i ++){ int x = read(); add1(i,i + n,x); } for(int i = 1; i <= m; i ++){ int x = read(),y = read(); add(x + n,y,inf); add(y + n,x,inf); } ll flow = 0; maxflow = 0; while(bfs()) while(flow = dinic(s,inf)) maxflow += flow; printf("%lld\n",maxflow); } } /* 3 1 2 3 2 2 6 */ ///連結:https://vjudge.net/problem/UVA-10480 /*題意: n個結點,m路徑,現在讓1和2號結點不要連線,破壞一條路徑的花費為k。 題解:最小割,輸出路徑的話,x和y一開始有路徑,x只和1號點連線,y只和2號點連線,那麼就是割邊。 鑑於此,本題我們用鄰接矩陣儲存更為方便; */ #include"stdio.h" #include"string.h" #include"stack" #include"map" #include"math.h" #include"iostream" #include"vector" #include"queue" #include"algorithm" using namespace std; #define OK printf("\n"); #define Debug printf("this_ok\n"); #define INF 0x3f3f3f3f typedef long long ll; #define scanll(a,b) scanf("%lld%lld",&a,&b); #define scanl(a) scanf("%lld",&a); #define printl(a,b) if(b == 0) printf("%lld ",a); else printf("%lld\n",a); #define print_int(a,b) if(b == 0) printf("%d ",a); else printf("%d\n",a); typedef pair<int,int> PII; inline int read(){ int s = 0, w = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') w = -1; ch = getchar(); } while(ch >= '0' && ch <= '9') { s = (s << 3) + (s << 1) + (ch ^ 48); ch = getchar(); } return s * w; } const ll mod = 998244353; const int N = 500010,M = 500010; const int inf = 1 << 29; const int maxn=1e3+10; int n,m; int mp[maxn][maxn];//初始流量 int flow[maxn][maxn];//最大流 int path[maxn];//記錄路徑 int a[maxn];//i點在最大流中的流量 int start,End; int x[maxn],y[maxn]; int maxflow() { queue<int> q; memset(flow,0,sizeof flow); int max_flow=0; while(true){ memset(a,0,sizeof a);//清空標記 a[start]=INF;//源點權值無限大 while(!q.empty()) q.pop(); q.push(start); while(!q.empty()){ int temp=q.front(); q.pop(); for(int i=1;i<=n;i++){ //未走過且流量小於他的權值 if(!a[i]&&flow[temp][i]<mp[temp][i]) { path[i]=temp;//記錄前一個點 a[i]=min(a[temp],mp[temp][i]-flow[temp][i]); q.push(i); } } } if(a[End]==0) break; //更新剩餘網路 for(int i=End;i!=start;i=path[i]){ flow[path[i]][i]+=a[End];//反向邊加 flow[i][path[i]]-=a[End];//正向邊減 } max_flow+=a[End]; } return max_flow; } int main() { while(~scanf("%d%d",&n,&m)){ if(n == 0) break; memset(mp,0,sizeof mp); for(int i=1;i<=m;i++) { int u = read(),v = read(),w = read(); mp[u][v]=mp[v][u]=w;///無向路徑 x[i]=u; y[i]=v; } start=1;End=2; int flow=maxflow(); for(int i=1;i<=m;i++){//列舉每一條邊的兩個點 //有一點的權值為0,說明當前點被刪除 if((!a[x[i]]&&a[y[i]])||(a[x[i]]&&!a[y[i]])) printf("%d %d\n",x[i],y[i]); } printf("\n"); } return 0; } ///連結:http://acm.hdu.edu.cn/showproblem.php?pid=4280 /*題意: 在最西邊的點走到最東邊的點最大容量。 題解:ISAP模板題,Dinic過不了。 */ #include"stdio.h" #include"string.h" #include"stack" #include"map" #include"math.h" #include"iostream" #include"string" #include"vector" #include"queue" #include"algorithm" using namespace std; #define OK printf("\n"); #define Debug printf("this_ok\n"); #define INF 1e18 typedef long long ll; #define scanll(a,b) scanf("%lld%lld",&a,&b); #define scanl(a) scanf("%lld",&a); #define printl(a,b) if(b == 0) printf("%lld ",a); else printf("%lld\n",a); #define print_int(a,b) if(b == 0) printf("%d ",a); else printf("%d\n",a); typedef pair<int,int> PII; inline int read(){ int s = 0, w = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') w = -1; ch = getchar(); } while(ch >= '0' && ch <= '9') { s = (s << 3) + (s << 1) + (ch ^ 48); ch = getchar(); } return s * w; } const ll mod = 998244353; const int N = 200000,M = 800000; const double pi = acos(-1); const int inf = 1 << 29; const int dirx[4] = {-1,0,1,0}; const int diry[4] = {0,1,0,-1}; int n,m,t,s,tot; ll maxflow,sum; int head[N],ver[M],Next[M],edge[M],d[N]; int w[N]; queue<int> q; map<string,int> Q; void add(int x,int y,int z){ ver[++ tot] = y; Next[tot] = head[x]; edge[tot] = z; head[x] = tot; ver[++ tot] = x; edge[tot] = z; Next[tot] = head[y]; head[y] = tot; } bool bfs(){ memset(d,0,sizeof(d)); while(q.size())q.pop(); q.push(s); d[s] = 1; while(q.size()){ int x = q.front(); q.pop(); for(int i = head[x]; i; i = Next[i]) if(edge[i] && !d[ver[i]]){ q.push(ver[i]); d[ver[i]] = d[x] + 1; if(ver[i] == t) return 1; } } return 0; } int dinic(int x,ll flow){ if(x == t) return flow; ll rest = flow,k; for(int i = head[x]; i && rest; i = Next[i]){ if(edge[i] && d[ver[i]] == d[x] + 1){ k = dinic(ver[i],min(rest,(ll)edge[i])); if(!k) d[ver[i]] = 0; edge[i] -= k; edge[i ^ 1] += k; rest -= k; } } return flow - rest; } int main(){ int T = read(); while(T --){ n = read(); m = read(); tot = 1;s = 1; t = 1; int tmax = -inf, tmin = inf; s = t= 1; for(int i = 1; i <= n; i ++) { int x = read(),y = read(); if(x >= tmax) tmax = x, t = i; if(x <= tmin) tmin = x, s = i; head[i] = 0; } for(int i = 1; i <= m; i ++){ int x = read(),y = read(),w = read(); add(x,y,w); } ll flow = 0; maxflow = 0; while(bfs()) while(flow = dinic(s,inf)) maxflow += flow; printf("%lld\n",maxflow); } } /* 3 1 2 3 2 2 6 #include <cstdio> #include <algorithm> #include <iostream> #include <cstring> #include <string> #include <cmath> #include <queue> #include <vector> #include <map> #include <set> using namespace std; #define INF 0x3f3f3f3f #define N 100010 typedef long long LL; struct Edge { int u, v; LL cap; Edge () {} Edge (int u, int v, LL cap) : u(u), v(v), cap(cap) {} }edge[N*4]; vector<int> G[N]; int dis[N], cur[N], num[N], pre[N], tot, S, T; void Add(int u, int v, int cap) { edge[tot] = Edge(u, v, cap); G[u].push_back(tot++); edge[tot] = Edge(v, u, cap); G[v].push_back(tot++); } int BFS() { // 逆向BFS memset(dis, -1, sizeof(dis)); queue<int> que; que.push(T); dis[T] = 0; while(!que.empty()) { int u = que.front(); que.pop(); for(int i = 0; i < G[u].size(); i++) { Edge &e = edge[G[u][i]]; if(dis[e.v] == -1) { dis[e.v] = dis[u] + 1; que.push(e.v); } } } return ~dis[S]; } int DFS() { // 通過pre陣列回溯更新流量 int u = T; int flow = INF; while(u != S) { Edge &e = edge[pre[u]]; if(e.cap < flow) flow = e.cap; u = e.u; } u = T; while(u != S) { Edge& e1 = edge[pre[u]]; Edge& e2 = edge[pre[u]^1]; e1.cap -= flow; e2.cap += flow; u = e1.u; } return flow; } int ISAP(int n) { if(!BFS()) return 0; // 從匯點到源點逆向BFS初始化dis陣列 memset(num, 0, sizeof(num)); memset(cur, 0, sizeof(cur)); // 當前弧優化 for(int i = 1; i <= n; i++) if(~dis[i]) num[dis[i]]++; // 當前距離為dis[i]的結點數 int ans = 0, u = S; while(dis[S] < n) { if(u == T) ans += DFS(), u = S; // 回溯之前的結點並把更新流量 int flag = 0; for(int i = 0; i < G[u].size(); i++) { Edge &e = edge[G[u][i]]; if(dis[e.v] + 1 == dis[u] && e.cap > 0) { // 可以增廣 pre[e.v] = G[u][i]; cur[u] = i; flag = 1; u = e.v; break; } } if(!flag) { // 不能增廣,retreat if(--num[dis[u]] == 0) break; // gap優化 int md = n; for(int i = 0; i < G[u].size(); i++) { Edge &e = edge[G[u][i]]; if(e.cap > 0 && dis[e.v] < md) { md = dis[e.v]; cur[u] = i; } } num[dis[u] = md + 1]++; if(u != S) u = edge[pre[u]].u; } } return ans; } int main() { int t; scanf("%d", &t); while(t--) { int n, m; scanf("%d%d", &n, &m); tot = 0; for(int i = 0; i <= n; i++) G[i].clear(); int u, v, c, west = 100000000, east = -10000000; for(int i = 1; i <= n; i++) { scanf("%d%d", &u, &v); if(west > u) west = u, S = i; if(east < u) east = u, T = i; } for(int i = 1; i <= m; i++) { scanf("%d%d%d", &u, &v, &c); Add(u, v, c); // 無向圖的話反向邊的cap也是c } printf("%d\n", ISAP(n)); } return 0; } */ ///連結:https://vjudge.net/problem/POJ-1087 /*題意: 有m個裝置需要插座(給出了每個裝置需要的插座型號),但是現在只有n個插座(任意兩個插座型別不相同,因為題目說每種型別插座就一個),且給你k個轉換器(轉換器(u,v)可以使得插座v轉接到u上),問你最多有幾個裝置沒有插座可用? 題解:建圖: 源點s(編號0)到每個裝置i有邊 (s,i,1). 每個插座到j到匯點t(編號n+m+1)有邊 (j,t,1) 如果裝置i對應的插座是j,那麼有邊(i,j,1) 如果轉換器對應(u,v)(說明可以把插座v轉接到u上),那麼有邊(u,v,INF) (因為轉換器無限個,且它可以把原本需要u插座的電器連到v插座上) */ #include"stdio.h" #include"string.h" #include"stack" #include"map" #include"math.h" #include"iostream" #include"string" #include"vector" #include"queue" #include"algorithm" using namespace std; #define OK printf("\n"); #define Debug printf("this_ok\n"); #define INF 1e18 typedef long long ll; #define scanll(a,b) scanf("%lld%lld",&a,&b); #define scanl(a) scanf("%lld",&a); #define printl(a,b) if(b == 0) printf("%lld ",a); else printf("%lld\n",a); #define print_int(a,b) if(b == 0) printf("%d ",a); else printf("%d\n",a); typedef pair<int,int> PII; inline int read(){ int s = 0, w = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') w = -1; ch = getchar(); } while(ch >= '0' && ch <= '9') { s = (s << 3) + (s << 1) + (ch ^ 48); ch = getchar(); } return s * w; } const ll mod = 998244353; const int N = 50010,M = 300010; const double pi = acos(-1); const int inf = 1 << 29; const int dirx[4] = {-1,0,1,0}; const int diry[4] = {0,1,0,-1}; int n,m,t,s,tot; ll maxflow,sum; int head[N],ver[M],Next[M],edge[M],d[N]; int w[N]; queue<int> q; map<string,int> Q; void add(int x,int y,int z){ ver[++ tot] = y; Next[tot] = head[x]; edge[tot] = z; head[x] = tot; ver[++ tot] = x; edge[tot] = 0; Next[tot] = head[y]; head[y] = tot; } bool bfs(){ memset(d,0,sizeof(d)); while(q.size())q.pop(); q.push(s); d[s] = 1; while(q.size()){ int x = q.front(); q.pop(); for(int i = head[x]; i; i = Next[i]) if(edge[i] && !d[ver[i]]){ q.push(ver[i]); d[ver[i]] = d[x] + 1; if(ver[i] == t) return 1; } } return 0; } int dinic(int x,ll flow){ if(x == t) return flow; ll rest = flow,k; for(int i = head[x]; i && rest; i = Next[i]){ if(edge[i] && d[ver[i]] == d[x] + 1){ k = dinic(ver[i],min(rest,(ll)edge[i])); if(!k) d[ver[i]] = 0; edge[i] -= k; edge[i ^ 1] += k; rest -= k; } } return flow - rest; } int main(){ n = read(); tot = 1;int top = 0; s = 0; t = 510; int p1[120] = {0},p2[120] = {0}; for(int i = 1; i <= n; i ++){ char str; cin >> str; p1[str - 'A' + 1] ++; } for(int i = 1; i < 120; i ++){ if(!p1[i]) continue; add(i,t,p1[i]); } m = read(); for(int i = 1; i <= m; i ++){ string name; char str; cin >> name >> str; p2[str - 'A' + 1] ++; } for(int i = 1; i < 120; i ++){ if(!p2[i]) continue; add(s,i + 120,p2[i]); // add(i + 120,i,inf); } int q = read(); for(int i = 1; i <= q; i ++){ char s1,s2; cin >> s1 >> s2; add(s1 - 'A' + 1 + 120,s2 - 'A' + 1 + 120,inf); } for(int i = 1; i < 120; i ++) add(i + 120,i,inf); ll flow = 0; while(bfs()) while(flow = dinic(s,inf)) maxflow += flow; printf("%lld\n",m - maxflow); } /* 3 1 2 3 2 2 6 */