日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

最小割小记

發布時間:2023/12/3 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 最小割小记 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

參考博客:最小割淺談

關于最小割

  • 常用描述
    表述一:刪去若干條邊使得源點到匯點不連通,求刪邊的權值和的最小可能值。
    表述二:將點集分為(S,T)(S,T)(S,T),記所有從SSS中出發到TTT中的邊的權值和為c(S,T)c(S,T)c(S,T),求c(S,T)c(S,T)c(S,T)的最小值。

  • 求最小割
    a. 以權值為容量,該網絡最大流的值即為最小割的值
    b. 在殘量網絡中,從源點出發進行一次增廣BFS,即得到一個分割。該分割是一個最小割。

  • 題型1:對求最小割原理的理解

    [AHOI2009]最小割



    摘自此Blog

    [SDOI2014]LIS



    摘自此Blog

    #include<algorithm> #include<iostream> #include<cstring> #include<cstdio> #include<queue> #define re register #define maxn 1505 #define LL long long #define inf 999999999 inline int max(int a,int b){return a>b?a:b;} inline int min(int a,int b){return a<b?a:b;} inline int read() {char c=getchar();int x=0;while(c<'0'||c>'9') c=getchar();while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x; } struct node{int a,b,c,rk;}g[maxn]; inline int cmp(node A,node B) {return A.c<B.c;} struct E{int v,nxt,w,f;}e[maxn*maxn]; int n,num=1,S,T,Test; int ans[maxn],cnt,id[maxn],vis[maxn]; int d[maxn],dp[maxn],head[maxn],cur[maxn],in[maxn],out[maxn]; inline void add(int x,int y,int z) {e[++num].v=y;e[num].nxt=head[x];head[x]=num;e[num].w=z;} inline void C(int x,int y,int z) {add(x,y,z),add(y,x,0);} inline int check(int s,int t) {std::queue<int> q;memset(vis,0,sizeof(vis));q.push(s);vis[s]=1;while(!q.empty()){int k=q.front();q.pop();if(k==t) return 1;for(re int i=head[k];i;i=e[i].nxt)if(!vis[e[i].v]&&e[i].w>e[i].f) q.push(e[i].v),vis[e[i].v]=1;}return 0; } inline int BFS(int s,int t) {std::queue<int> q;memcpy(cur,head,sizeof(head));memset(d,0,sizeof(d));d[s]=1,q.push(s);while(!q.empty()){int k=q.front();q.pop();for(re int i=head[k];i;i=e[i].nxt)if(!d[e[i].v]&&e[i].w>e[i].f) {d[e[i].v]=d[k]+1;if(e[i].v==t) return 1;q.push(e[i].v);}}return d[t]; } int dfs(int x,int now,int t) {if(x==t||!now) return now;int flow=0,ff;for(re int& i=cur[x];i;i=e[i].nxt)if(d[e[i].v]==d[x]+1){ff=dfs(e[i].v,min(now,e[i].w-e[i].f),t);if(ff<=0) continue;now-=ff,flow+=ff;e[i].f+=ff,e[i^1].f-=ff;if(!now) break;}return flow; } int main() {Test=read();while(Test--){n=read();cnt=0;num=1;memset(head,0,sizeof(head));for(re int i=1;i<=n;i++) g[i].a=read(),dp[i]=1;for(re int i=1;i<=n;i++) g[i].b=read(),g[i].rk=i;for(re int i=1;i<=n;i++)for(re int j=1;j<i;j++) if(g[j].a<g[i].a) dp[i]=max(dp[j]+1,dp[i]);int tot=0;for(re int i=1;i<=n;i++) tot=max(tot,dp[i]);//dp求LIS T=0;for(re int i=1;i<=n;i++) in[i]=++T;for(re int i=1;i<=n;i++) out[i]=++T;++T;for(re int i=1;i<=n;i++) C(in[i],out[i],g[i].b),id[i]=num;for(re int i=1;i<=n;i++) if(dp[i]==1) C(S,in[i],inf);for(re int i=1;i<=n;i++) if(dp[i]==tot) C(out[i],T,inf);for(re int i=1;i<=n;i++)for(re int j=1;j<i;j++) if(g[j].a<g[i].a&&dp[j]+1==dp[i]) C(out[j],in[i],inf);tot=0;while(BFS(S,T)) tot+=dfs(S,inf,T);//建圖+跑最小割 for(re int i=1;i<=n;i++) g[i].c=read();printf("%d ",tot);std::sort(g+1,g+n+1,cmp);for(re int i=1;i<=n;i++){int k=g[i].rk;if(check(in[k],out[k])) continue;ans[++cnt]=k;while(BFS(T,out[k])) dfs(T,inf,out[k]);while(BFS(in[k],S)) dfs(in[k],inf,S);e[id[k]].w=e[id[k]^1].w=0;e[id[k]].f=e[id[k]^1].f=0;//退流,排除和當前所選邊等價的邊的影響 }printf("%d\n",cnt);std::sort(ans+1,ans+cnt+1);for(re int i=1;i<=cnt;i++) printf("%d ",ans[i]);putchar(10);}return 0; }

    題型2:最下生成樹相關

    例題這里有

    題型3:對點的分割 轉 對邊的分割

    [HNOI2013] 切糕

    題型4:最小點割集

    最小點割集是指:
    給出一張有向圖(無向圖)和兩個點S、T,每個點都有一個正數點權,求一個不包含點S、T的權值和最小的點集使得刪掉點集中的所有點后,S無法到達T。

    求法:
    對于這個問題,我們將每一個點拆成兩個點,一個為入點,一個為出點,這兩個點之間有一條邊權為原圖中點權的有向邊,從入點指向出點。對于原圖中的邊x→yx\to yxy,我們將其更改為x的出點→y\to yy的入點。在轉化完的圖上跑最小割就是原圖的最小點割集。

    題型5:最小割樹——求任意兩點的最小割

    最小割樹

    #include<bits/stdc++.h> using namespace std; int n,m,node[505],dep[505],fa[505][10],mn[505][10]; int cnt,top[505],to[1005],len[1005],nex[1005]; int read() {int re=0;char ch=getchar();while(!isdigit(ch)) ch=getchar();while(isdigit(ch)) re=(re<<3)+(re<<1)+ch-'0',ch=getchar();return re; } void add_edge(int x,int y,int z) {to[++cnt]=y,len[cnt]=z,nex[cnt]=top[x],top[x]=cnt;to[++cnt]=x,len[cnt]=z,nex[cnt]=top[y],top[y]=cnt; } namespace GHT {int s,t;int tot,cur[505],dep[505],col[505],col_bucket[505];int cnt=1,top[505],to[3005],cap[3005],flow[3005],nex[3005];void add_edge(int x,int y,int z){to[++cnt]=y,cap[cnt]=z,flow[cnt]=0,nex[cnt]=top[x],top[x]=cnt;to[++cnt]=x,cap[cnt]=z,flow[cnt]=0,nex[cnt]=top[y],top[y]=cnt;//注意這里 }bool BFS(){memset(cur,0,sizeof cur);memset(dep,0,sizeof dep);dep[s]=1,cur[s]=top[s];queue<int>Q;Q.push(s);while(!Q.empty()){int now=Q.front();Q.pop();for(int i=top[now];i;i=nex[i])if(!dep[to[i]]&&cap[i]>flow[i]){dep[to[i]]=dep[now]+1;cur[to[i]]=top[to[i]];Q.push(to[i]);}}return dep[t]!=0;}int DFS(int now,int rest){if(now==t) return rest;int re=0;for(int &i=cur[now];i;i=nex[i])if(dep[to[i]]==dep[now]+1&&cap[i]>flow[i]){int lzq=DFS(to[i],min(rest,cap[i]-flow[i]));if(lzq){rest-=lzq,re+=lzq;flow[i]+=lzq,flow[i^1]-=lzq;//注意這里 if(!rest) break;}}return re;}int Dinic(int x,int y){int re=0;s=x,t=y;for(int i=1;i<=cnt;i++) flow[i]=0;while(BFS()) re+=DFS(s,0x3f3f3f3f);return re;}void get_color(int now,int color){col[now]=color;for(int i=top[now];i;i=nex[i])if(cap[i]>flow[i]&&col[to[i]]!=color)//注意這里 get_color(to[i],color);}void build(int l,int r){if(l==r) return ;int x=node[l],y=node[l+1];int cut=Dinic(x,y);get_color(x,++tot);int L=l,R=r;for(int i=l;i<=r;i++)if(col[node[i]]==tot) col_bucket[L++]=node[i];else col_bucket[R--]=node[i];for(int i=l;i<=r;i++) node[i]=col_bucket[i];::add_edge(x,y,cut);build(l,L-1);build(R+1,r);} } void dfs(int now) {for(int i=1;i<=9;i++){fa[now][i]=fa[fa[now][i-1]][i-1];mn[now][i]=min(mn[now][i-1],mn[fa[now][i-1]][i-1]);}for(int i=top[now];i;i=nex[i]){if(to[i]==fa[now][0]) continue;dep[to[i]]=dep[now]+1,fa[to[i]][0]=now,mn[to[i]][0]=len[i];dfs(to[i]);} } int getcut(int x,int y) {int re=INT_MAX;if(dep[x]<dep[y]) swap(x,y);for(int i=9;i>=0;i--) if(dep[fa[x][i]]>=dep[y]) re=min(re,mn[x][i]),x=fa[x][i];if(x==y) return re;for(int i=9;i>=0;i--) if(fa[x][i]!=fa[y][i]) re=min(re,min(mn[x][i],mn[y][i])),x=fa[x][i],y=fa[y][i];return min(re,min(mn[x][0],mn[y][0])); } int main() {n=read(),m=read();while(m--){int x=read(),y=read(),z=read();GHT::add_edge(x,y,z);}for(int i=1;i<=n;i++) node[i]=i;GHT::build(1,n);dep[1]=1;dfs(1);m=read();while(m--){int x=read(),y=read();printf("%d\n",getcut(x,y));}return 0; }

    題型6:最大權閉合子圖

    閉合子圖指的是,對于有向圖,我們選擇一些點,在這個點集之中,沒有一個點的出邊指向非此點集中的點,但是可以有其他點的出邊指向這個點集之中。所說的最大權閉合子圖,就是在這個圖的所有閉合子圖中點權和最大的。

    求法:
    建立源點,向每一個點權為正的點連邊,邊權為該點的權值。建立匯點,向每一個點權為負連邊,邊權為該點的權值的絕對值。原圖中的邊進行保留,邊權為infinfinf。最大權閉合子圖就是所有的點權為正的點權和減去最小割。


    題型7:劃分點集

    (u→v,w)(u\to v,w)(uv,w)為一條從uuuvvv,權值為www的邊。

    基礎模型

    nnn個點劃分到兩個集合A,BA,BA,B。給出若干形如 “若…,則有…的代價/貢獻” 的條件。問最大貢獻/最小代價是多少。

    如果題目問的是最小代價,直接按下面方法連邊求最小割。
    如果題目問的是最大貢獻,答案為∑所有可能貢獻?最小代價(最小割)\sum 所有可能貢獻-最小代價(最小割)?()

    定義和SSS相連的點劃到AAA集合,和TTT相連的點劃到BBB集合,那么我們可以按下面的方法處理題目給出的條件:

  • 條件-表述1:若把iii劃到AAA,則要付出bib_ibi?的代價;若把iii劃到BBB,則要付出aia_iai?的代價
    條件-表述2:若把iii劃到BBB,則有bib_ibi?的貢獻;若把iii劃到AAA,則有aia_iai?的貢獻
    方案:(i→T,bi)(i\to T,b_i)(iT,bi?),(S→i,ai)(S\to i,a_i)(Si,ai?)
  • 條件-表述1:若點集XXX中有元素劃到BBB,則要付出ccc的代價
    條件-表述2:若點集XXX中元素全部劃到AAA,則有ccc的貢獻
    方案:(S→new,c),?i∈X(new→i,inf)(S\to new,c),\forall i\in X(new\to i,inf)(Snew,c),?iX(newi,inf)
  • 條件-表述1:若點集XXX中有元素劃到AAA,則要付出ddd的代價
    條件-表述2:若點集XXX中元素全部劃到BBB,則有ddd的貢獻
    方案:?i∈X(i→new,inf),(new→T,d)\forall i\in X(i\to new,inf),(new\to T,d)?iX(inew,inf),(newT,d)
  • 條件:若點集XXX中有元素劃到BBB,點集YYY中有元素劃到AAA,則要付出eee的代價
    常見形式:若點iii劃到BBB,點jjj劃到AAA,則要付出eee的代價
    方案:?i∈X(new1→i,inf)\forall i\in X(new1\to i,inf)?iX(new1i,inf),?j∈Y(j→new2,inf)\forall j\in Y(j\to new2,inf)?jY(jnew2,inf),(new2→new1,e)(new2\to new1,e)(new2new1,e)
  • 條件:若點集XXX中有元素劃到AAA,點集YYY中有元素劃到BBB,則要付出fff的代價
    常見形式:若點iii劃到AAA,點jjj劃到BBB,則要付出fff的代價
    方案:?i∈X(i→new1,inf)\forall i\in X(i\to new1,inf)?iX(inew1,inf),?j∈Y(new2→j,inf)\forall j\in Y(new2\to j,inf)?jY(new2j,inf),(new1→new2,f)(new1\to new2,f)(new1new2,f)
  • [Shoi2007]Vote 善意的投票

    BZOJ3438: 小M的作物

    [BZOJ3218]a + b Problem

    處理變形問題的trick:黑白染色,翻轉源匯

    對于“x,yx,yx,y必須劃到不同集合” “x,yx,yx,y劃到不同集合有ccc的貢獻” “x,yx,yx,y劃到相同集合有ddd的代價”這樣的條件,我們可以連邊(x,y)(x,y)(x,y),黑白染色后x,yx,yx,y一定一個是黑點,一個是白點。

    如果將其中一種顏色的點進行翻轉源匯,即原本應該連向SSS的邊連向TTT,原本應該連向TTT的邊連向SSS,那么“x,yx,yx,y在不同集合”就變成了“x,yx,yx,y在相同集合”,“x,yx,yx,y在相同集合”就變成了“x,yx,yx,y在不同集合”

    BZOJ1324Exca王者之劍&BZOJ1475方格取數——二分圖最大獨立集

    [BZOJ2132]圈地計劃——翻轉源匯

    總結

    以上是生活随笔為你收集整理的最小割小记的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。